Skip to content

Commit

Permalink
Add support for nvme devices
Browse files Browse the repository at this point in the history
This also seems to avoid the disk corruption that we see
with virtio-blk; it reportedly has a small performance hit
for raw speed, but I think avoiding the double caching (guest and host)
is much better from a performance perspective.

Signed-off-by: Colin Walters <walters@verbum.org>
  • Loading branch information
cgwalters committed Jan 9, 2024
1 parent 7572104 commit 15b00ac
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 0 deletions.
16 changes: 16 additions & 0 deletions pkg/config/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ const (
vfGpu vmComponentKind = "virtiogpu"
vfInput vmComponentKind = "virtioinput"
usbMassStorage vmComponentKind = "usbmassstorage"
nvme vmComponentKind = "nvme"
rosetta vmComponentKind = "rosetta"
)

Expand Down Expand Up @@ -109,6 +110,10 @@ func unmarshalDevice(rawMsg json.RawMessage) (VirtioDevice, error) {
var newDevice VirtioBlk
err = json.Unmarshal(rawMsg, &newDevice)
dev = &newDevice
case nvme:
var newDevice NVMExpressController
err = json.Unmarshal(rawMsg, &newDevice)
dev = &newDevice
case vfFs:
var newDevice VirtioFs
err = json.Unmarshal(rawMsg, &newDevice)
Expand Down Expand Up @@ -258,6 +263,17 @@ func (dev *VirtioFs) MarshalJSON() ([]byte, error) {
})
}

func (dev *NVMExpressController) MarshalJSON() ([]byte, error) {
type devWithKind struct {
jsonKind
NVMExpressController
}
return json.Marshal(devWithKind{
jsonKind: kind(nvme),
NVMExpressController: *dev,
})
}

func (dev *RosettaShare) MarshalJSON() ([]byte, error) {
type devWithKind struct {
jsonKind
Expand Down
29 changes: 29 additions & 0 deletions pkg/config/virtio.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ type RosettaShare struct {
InstallRosetta bool
}

// NVMExpressController configures a NVMe controller in the guest
type NVMExpressController struct {
StorageConfig
}

// virtioRng configures a random number generator (RNG) device.
type VirtioRng struct {
}
Expand Down Expand Up @@ -143,6 +148,8 @@ func deviceFromCmdLine(deviceOpts string) (VirtioDevice, error) {
switch opts[0] {
case "rosetta":
dev = &RosettaShare{}
case "nvme":
dev = nvmExpressControllerNewEmpty()
case "virtio-blk":
dev = virtioBlkNewEmpty()
case "virtio-fs":
Expand Down Expand Up @@ -452,6 +459,28 @@ func (dev *VirtioRng) FromOptions(options []option) error {
return nil
}

func nvmExpressControllerNewEmpty() *NVMExpressController {
return &NVMExpressController{
StorageConfig: StorageConfig{
DevName: "nvme",
},
}
}

func NVMExpressControllerNew(imagePath string) (*NVMExpressController, error) {
r := nvmExpressControllerNewEmpty()
r.ImagePath = imagePath
return r, nil
}

func (dev *NVMExpressController) FromOptions(options []option) error {
return dev.StorageConfig.FromOptions(options)
}

func (dev *NVMExpressController) ToCmdLine() ([]string, error) {
return dev.StorageConfig.ToCmdLine()
}

func virtioBlkNewEmpty() *VirtioBlk {
return &VirtioBlk{
StorageConfig: StorageConfig{
Expand Down
10 changes: 10 additions & 0 deletions pkg/config/virtio_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@ var virtioDevTests = map[string]virtioDevTest{
expectedCmdLine: []string{"--device", "virtio-blk,path=/foo/bar,deviceId=test"},
alternateCmdLine: []string{"--device", "virtio-blk,deviceId=test,path=/foo/bar"},
},
"NewNVMe": {
newDev: func() (VirtioDevice, error) { return NVMExpressControllerNew("/foo/bar") },
expectedDev: &NVMExpressController{
StorageConfig: StorageConfig{
DevName: "nvme",
ImagePath: "/foo/bar",
},
},
expectedCmdLine: []string{"--device", "nvme,path=/foo/bar"},
},
"NewVirtioFs": {
newDev: func() (VirtioDevice, error) { return VirtioFsNew("/foo/bar", "") },
expectedDev: &VirtioFs{
Expand Down
28 changes: 28 additions & 0 deletions pkg/vf/virtio.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
)

type RosettaShare config.RosettaShare
type NVMExpressController config.NVMExpressController
type VirtioBlk config.VirtioBlk
type VirtioFs config.VirtioFs
type VirtioRng config.VirtioRng
Expand All @@ -22,6 +23,31 @@ type VirtioVsock config.VirtioVsock
type VirtioInput config.VirtioInput
type VirtioGPU config.VirtioGPU

func (dev *NVMExpressController) toVz() (vz.StorageDeviceConfiguration, error) {
var storageConfig StorageConfig = StorageConfig(dev.StorageConfig)
attachment, err := storageConfig.toVz()
if err != nil {
return nil, err
}
devConfig, err := vz.NewNVMExpressControllerDeviceConfiguration(attachment)
if err != nil {
return nil, err
}

return devConfig, nil
}

func (dev *NVMExpressController) AddToVirtualMachineConfig(vmConfig *vzVirtualMachineConfiguration) error {
storageDeviceConfig, err := dev.toVz()
if err != nil {
return err
}
log.Infof("Adding nvme device (imagePath: %s)", dev.ImagePath)
vmConfig.storageDevicesConfiguration = append(vmConfig.storageDevicesConfiguration, storageDeviceConfig)

return nil
}

func (dev *VirtioBlk) toVz() (vz.StorageDeviceConfiguration, error) {
var storageConfig StorageConfig = StorageConfig(dev.StorageConfig)
attachment, err := storageConfig.toVz()
Expand Down Expand Up @@ -251,6 +277,8 @@ func AddToVirtualMachineConfig(dev config.VirtioDevice, vmConfig *vzVirtualMachi
return (*VirtioBlk)(d).AddToVirtualMachineConfig(vmConfig)
case *config.RosettaShare:
return (*RosettaShare)(d).AddToVirtualMachineConfig(vmConfig)
case *config.NVMExpressController:
return (*NVMExpressController)(d).AddToVirtualMachineConfig(vmConfig)
case *config.VirtioFs:
return (*VirtioFs)(d).AddToVirtualMachineConfig(vmConfig)
case *config.VirtioNet:
Expand Down

0 comments on commit 15b00ac

Please sign in to comment.