diff --git a/qemu/qmp.go b/qemu/qmp.go index 40e4781a69..efa672b61a 100644 --- a/qemu/qmp.go +++ b/qemu/qmp.go @@ -670,7 +670,8 @@ func (q *QMP) ExecuteBlockdevAdd(ctx context.Context, device, blockdevID string) // to a previous call to ExecuteBlockdevAdd. devID is the id of the device to // add. Both strings must be valid QMP identifiers. driver is the name of the // driver,e.g., virtio-blk-pci, and bus is the name of the bus. bus is optional. -func (q *QMP) ExecuteDeviceAdd(ctx context.Context, blockdevID, devID, driver, bus string) error { +// shared denotes if the drive can be shared allowing it to be passed more than once. +func (q *QMP) ExecuteDeviceAdd(ctx context.Context, blockdevID, devID, driver, bus string, shared bool) error { args := map[string]interface{}{ "id": devID, "driver": driver, @@ -679,6 +680,9 @@ func (q *QMP) ExecuteDeviceAdd(ctx context.Context, blockdevID, devID, driver, b if bus != "" { args["bus"] = bus } + if shared && (q.version.Major > 2 || (q.version.Major == 2 && q.version.Minor >= 10)) { + args["share-rw"] = "on" + } return q.executeCommand(ctx, "device_add", args, nil) } @@ -688,8 +692,9 @@ func (q *QMP) ExecuteDeviceAdd(ctx context.Context, blockdevID, devID, driver, b // the device to add. Both strings must be valid QMP identifiers. driver is the name of the // scsi driver,e.g., scsi-hd, and bus is the name of a SCSI controller bus. // scsiID is the SCSI id, lun is logical unit number. scsiID and lun are optional, a negative value -// for scsiID and lun is ignored. -func (q *QMP) ExecuteSCSIDeviceAdd(ctx context.Context, blockdevID, devID, driver, bus string, scsiID, lun int) error { +// for scsiID and lun is ignored. shared denotes if the drive can be shared allowing it +// to be passed more than once. +func (q *QMP) ExecuteSCSIDeviceAdd(ctx context.Context, blockdevID, devID, driver, bus string, scsiID, lun int, shared bool) error { // TBD: Add drivers for scsi passthrough like scsi-generic and scsi-block drivers := []string{"scsi-hd", "scsi-cd", "scsi-disk"} @@ -717,6 +722,9 @@ func (q *QMP) ExecuteSCSIDeviceAdd(ctx context.Context, blockdevID, devID, drive if lun >= 0 { args["lun"] = lun } + if shared && (q.version.Major > 2 || (q.version.Major == 2 && q.version.Minor >= 10)) { + args["share-rw"] = "on" + } return q.executeCommand(ctx, "device_add", args, nil) } @@ -802,8 +810,9 @@ func (q *QMP) ExecuteDeviceDel(ctx context.Context, devID string) error { // ExecutePCIDeviceAdd is the PCI version of ExecuteDeviceAdd. This function can be used // to hot plug PCI devices on PCI(E) bridges, unlike ExecuteDeviceAdd this function receive the -// device address on its parent bus. bus is optional. -func (q *QMP) ExecutePCIDeviceAdd(ctx context.Context, blockdevID, devID, driver, addr, bus string) error { +// device address on its parent bus. bus is optional. shared denotes if the drive can be shared +// allowing it to be passed more than once. +func (q *QMP) ExecutePCIDeviceAdd(ctx context.Context, blockdevID, devID, driver, addr, bus string, shared bool) error { args := map[string]interface{}{ "id": devID, "driver": driver, @@ -813,6 +822,10 @@ func (q *QMP) ExecutePCIDeviceAdd(ctx context.Context, blockdevID, devID, driver if bus != "" { args["bus"] = bus } + if shared && (q.version.Major > 2 || (q.version.Major == 2 && q.version.Minor >= 10)) { + args["share-rw"] = "on" + } + return q.executeCommand(ctx, "device_add", args, nil) } diff --git a/qemu/qmp_test.go b/qemu/qmp_test.go index c6c4ed4f00..4ebda65d6d 100644 --- a/qemu/qmp_test.go +++ b/qemu/qmp_test.go @@ -438,11 +438,11 @@ func TestQMPDeviceAdd(t *testing.T) { buf.AddCommand("device_add", nil, "return", nil) cfg := QMPConfig{Logger: qmpTestLogger{}} q := startQMPLoop(buf, cfg, connectedCh, disconnectedCh) - checkVersion(t, connectedCh) + q.version = checkVersion(t, connectedCh) blockdevID := fmt.Sprintf("drive_%s", volumeUUID) devID := fmt.Sprintf("device_%s", volumeUUID) err := q.ExecuteDeviceAdd(context.Background(), blockdevID, devID, - "virtio-blk-pci", "") + "virtio-blk-pci", "", true) if err != nil { t.Fatalf("Unexpected error %v", err) } @@ -463,11 +463,11 @@ func TestQMPSCSIDeviceAdd(t *testing.T) { buf.AddCommand("device_add", nil, "return", nil) cfg := QMPConfig{Logger: qmpTestLogger{}} q := startQMPLoop(buf, cfg, connectedCh, disconnectedCh) - checkVersion(t, connectedCh) + q.version = checkVersion(t, connectedCh) blockdevID := fmt.Sprintf("drive_%s", volumeUUID) devID := fmt.Sprintf("device_%s", volumeUUID) err := q.ExecuteSCSIDeviceAdd(context.Background(), blockdevID, devID, - "scsi-hd", "scsi0.0", 1, 2) + "scsi-hd", "scsi0.0", 1, 2, true) if err != nil { t.Fatalf("Unexpected error %v", err) } @@ -881,11 +881,11 @@ func TestQMPPCIDeviceAdd(t *testing.T) { buf.AddCommand("device_add", nil, "return", nil) cfg := QMPConfig{Logger: qmpTestLogger{}} q := startQMPLoop(buf, cfg, connectedCh, disconnectedCh) - checkVersion(t, connectedCh) + q.version = checkVersion(t, connectedCh) blockdevID := fmt.Sprintf("drive_%s", volumeUUID) devID := fmt.Sprintf("device_%s", volumeUUID) err := q.ExecutePCIDeviceAdd(context.Background(), blockdevID, devID, - "virtio-blk-pci", "0x1", "") + "virtio-blk-pci", "0x1", "", true) if err != nil { t.Fatalf("Unexpected error %v", err) }