Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pkg/driver/krunkit/krunkit_darwin_arm64.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func Cmdline(inst *limatype.Instance) (*exec.Cmd, error) {
"--restful-uri", "none://",

// First virtio-blk device is the boot disk
"--device", fmt.Sprintf("virtio-blk,path=%s,format=raw", filepath.Join(inst.Dir, filenames.DiffDisk)),
"--device", fmt.Sprintf("virtio-blk,path=%s,format=raw", filepath.Join(inst.Dir, filenames.Disk)),
"--device", fmt.Sprintf("virtio-blk,path=%s", filepath.Join(inst.Dir, filenames.CIDataISO)),
}

Expand Down
86 changes: 37 additions & 49 deletions pkg/driver/qemu/qemu.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,42 +87,46 @@ func minimumQemuVersion() (hardMin, softMin semver.Version) {
return hardMin, softMin
}

// EnsureDisk also ensures the kernel and the initrd.
// EnsureDisk creates the VM disk from the downloaded image.
// For non-ISO images, it validates and symlinks the image as "disk".
// For ISO images, it symlinks the image as "iso" and creates an empty qcow2 disk.
func EnsureDisk(ctx context.Context, cfg Config) error {
diffDisk := filepath.Join(cfg.InstanceDir, filenames.DiffDisk)
if _, err := os.Stat(diffDisk); err == nil || !errors.Is(err, os.ErrNotExist) {
// disk is already ensured
diskPath := filepath.Join(cfg.InstanceDir, filenames.Disk)
if _, err := os.Stat(diskPath); err == nil || !errors.Is(err, os.ErrNotExist) {
return err
}

baseDisk := filepath.Join(cfg.InstanceDir, filenames.BaseDisk)

diskSize, _ := units.RAMInBytes(*cfg.LimaYAML.Disk)
if diskSize == 0 {
return nil
}
isBaseDiskISO, err := iso9660util.IsISO9660(baseDisk)
imagePath := filepath.Join(cfg.InstanceDir, filenames.Image)
isISO, err := iso9660util.IsISO9660(imagePath)
if err != nil {
return err
}
baseDiskInfo, err := qemuimgutil.GetInfo(ctx, baseDisk)
imageInfo, err := qemuimgutil.GetInfo(ctx, imagePath)
if err != nil {
return fmt.Errorf("failed to get the information of base disk %q: %w", baseDisk, err)
return fmt.Errorf("failed to get the information of %q: %w", imagePath, err)
}
if err = qemuimgutil.AcceptableAsBaseDisk(baseDiskInfo); err != nil {
return fmt.Errorf("file %q is not acceptable as the base disk: %w", baseDisk, err)
if err = qemuimgutil.AcceptableAsBaseDisk(imageInfo); err != nil {
return fmt.Errorf("file %q is not acceptable as a disk image: %w", imagePath, err)
}
if baseDiskInfo.Format == "" {
return fmt.Errorf("failed to inspect the format of %q", baseDisk)
if imageInfo.Format == "" {
return fmt.Errorf("failed to inspect the format of %q", imagePath)
}
args := []string{"create", "-f", "qcow2"}
if !isBaseDiskISO {
args = append(args, "-F", baseDiskInfo.Format, "-b", baseDisk)
}
args = append(args, diffDisk, strconv.Itoa(int(diskSize)))
cmd := exec.CommandContext(ctx, "qemu-img", args...)
if out, err := cmd.CombinedOutput(); err != nil {
return fmt.Errorf("failed to run %v: %q: %w", cmd.Args, string(out), err)
if isISO {
isoPath := filepath.Join(cfg.InstanceDir, filenames.ISO)
if err = os.Symlink(filenames.Image, isoPath); err != nil {
return err
}
diskSize, _ := units.RAMInBytes(*cfg.LimaYAML.Disk)
args := []string{"create", "-f", "qcow2", diskPath, strconv.Itoa(int(diskSize))}
cmd := exec.CommandContext(ctx, "qemu-img", args...)
if out, err := cmd.CombinedOutput(); err != nil {
os.Remove(isoPath)
return fmt.Errorf("failed to run %v: %q: %w", cmd.Args, string(out), err)
}
} else {
if err = os.Symlink(filenames.Image, diskPath); err != nil {
return err
}
}
return nil
}
Expand Down Expand Up @@ -152,8 +156,8 @@ func sendHmpCommand(cfg Config, cmd, tag string) (string, error) {
}

func execImgCommand(ctx context.Context, cfg Config, args ...string) (string, error) {
diffDisk := filepath.Join(cfg.InstanceDir, filenames.DiffDisk)
args = append(args, diffDisk)
diskPath := filepath.Join(cfg.InstanceDir, filenames.Disk)
args = append(args, diskPath)
logrus.Debugf("Running qemu-img %v command", args)
cmd := exec.CommandContext(ctx, "qemu-img", args...)
b, err := cmd.Output()
Expand Down Expand Up @@ -687,8 +691,8 @@ func Cmdline(ctx context.Context, cfg Config) (exe string, args []string, err er
}

// Disk
baseDisk := filepath.Join(cfg.InstanceDir, filenames.BaseDisk)
diffDisk := filepath.Join(cfg.InstanceDir, filenames.DiffDisk)
diskPath := filepath.Join(cfg.InstanceDir, filenames.Disk)
isoPath := filepath.Join(cfg.InstanceDir, filenames.ISO)
extraDisks := []string{}
for _, d := range y.AdditionalDisks {
diskName := d.Name
Expand Down Expand Up @@ -719,31 +723,15 @@ func Cmdline(ctx context.Context, cfg Config) (exe string, args []string, err er
extraDisks = append(extraDisks, dataDisk)
}

isBaseDiskCDROM, err := iso9660util.IsISO9660(baseDisk)
if err != nil {
return "", nil, err
if osutil.FileExists(diskPath) {
args = append(args, "-drive", fmt.Sprintf("file=%s,if=virtio,discard=on", diskPath))
}
if isBaseDiskCDROM {
if osutil.FileExists(isoPath) {
args = appendArgsIfNoConflict(args, "-boot", "order=d,splash-time=0,menu=on")
args = append(args, "-drive", fmt.Sprintf("file=%s,format=raw,media=cdrom,readonly=on", baseDisk))
args = append(args, "-drive", fmt.Sprintf("file=%s,format=raw,media=cdrom,readonly=on", isoPath))
} else {
args = appendArgsIfNoConflict(args, "-boot", "order=c,splash-time=0,menu=on")
}
if diskSize, _ := units.RAMInBytes(*cfg.LimaYAML.Disk); diskSize > 0 {
args = append(args, "-drive", fmt.Sprintf("file=%s,if=virtio,discard=on", diffDisk))
} else if !isBaseDiskCDROM {
baseDiskInfo, err := qemuimgutil.GetInfo(ctx, baseDisk)
if err != nil {
return "", nil, fmt.Errorf("failed to get the information of %q: %w", baseDisk, err)
}
if err = qemuimgutil.AcceptableAsBaseDisk(baseDiskInfo); err != nil {
return "", nil, fmt.Errorf("file %q is not acceptable as the base disk: %w", baseDisk, err)
}
if baseDiskInfo.Format == "" {
return "", nil, fmt.Errorf("failed to inspect the format of %q", baseDisk)
}
args = append(args, "-drive", fmt.Sprintf("file=%s,format=%s,if=virtio,discard=on", baseDisk, baseDiskInfo.Format))
}
for _, extraDisk := range extraDisks {
args = append(args, "-drive", fmt.Sprintf("file=%s,if=virtio,discard=on", extraDisk))
}
Expand Down
45 changes: 21 additions & 24 deletions pkg/driver/vz/vm_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ import (

"github.com/lima-vm/lima/v2/pkg/hostagent/events"
"github.com/lima-vm/lima/v2/pkg/imgutil/proxyimgutil"
"github.com/lima-vm/lima/v2/pkg/iso9660util"
"github.com/lima-vm/lima/v2/pkg/limatype"
"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
"github.com/lima-vm/lima/v2/pkg/limayaml"
Expand Down Expand Up @@ -486,41 +485,39 @@ func validateDiskFormat(diskPath string) error {
}

func attachDisks(ctx context.Context, inst *limatype.Instance, vmConfig *vz.VirtualMachineConfiguration) error {
baseDiskPath := filepath.Join(inst.Dir, filenames.BaseDisk)
diffDiskPath := filepath.Join(inst.Dir, filenames.DiffDisk)
diskPath := filepath.Join(inst.Dir, filenames.Disk)
isoPath := filepath.Join(inst.Dir, filenames.ISO)
ciDataPath := filepath.Join(inst.Dir, filenames.CIDataISO)
isBaseDiskCDROM, err := iso9660util.IsISO9660(baseDiskPath)
if err != nil {
return err
}
var configurations []vz.StorageDeviceConfiguration

if isBaseDiskCDROM {
if err = validateDiskFormat(baseDiskPath); err != nil {
if osutil.FileExists(diskPath) {
if err := validateDiskFormat(diskPath); err != nil {
return err
}
baseDiskAttachment, err := vz.NewDiskImageStorageDeviceAttachment(baseDiskPath, true)
diskAttachment, err := vz.NewDiskImageStorageDeviceAttachmentWithCacheAndSync(diskPath, false, diskImageCachingMode, vz.DiskImageSynchronizationModeFsync)
if err != nil {
return err
}
baseDisk, err := vz.NewUSBMassStorageDeviceConfiguration(baseDiskAttachment)
diskDev, err := vz.NewVirtioBlockDeviceConfiguration(diskAttachment)
if err != nil {
return err
}
configurations = append(configurations, baseDisk)
}
if err = validateDiskFormat(diffDiskPath); err != nil {
return err
configurations = append(configurations, diskDev)
}
diffDiskAttachment, err := vz.NewDiskImageStorageDeviceAttachmentWithCacheAndSync(diffDiskPath, false, diskImageCachingMode, vz.DiskImageSynchronizationModeFsync)
if err != nil {
return err
}
diffDisk, err := vz.NewVirtioBlockDeviceConfiguration(diffDiskAttachment)
if err != nil {
return err
if osutil.FileExists(isoPath) {
if err := validateDiskFormat(isoPath); err != nil {
return err
}
isoAttachment, err := vz.NewDiskImageStorageDeviceAttachment(isoPath, true)
if err != nil {
return err
}
isoDev, err := vz.NewUSBMassStorageDeviceConfiguration(isoAttachment)
if err != nil {
return err
}
configurations = append(configurations, isoDev)
}
configurations = append(configurations, diffDisk)

diskUtil := proxyimgutil.NewDiskUtil(ctx)

Expand Down Expand Up @@ -557,7 +554,7 @@ func attachDisks(ctx context.Context, inst *limatype.Instance, vmConfig *vz.Virt
configurations = append(configurations, extraDisk)
}

if err = validateDiskFormat(ciDataPath); err != nil {
if err := validateDiskFormat(ciDataPath); err != nil {
return err
}
ciDataAttachment, err := vz.NewDiskImageStorageDeviceAttachment(ciDataPath, true)
Expand Down
2 changes: 1 addition & 1 deletion pkg/driver/wsl2/fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import (

// EnsureFs downloads the root fs.
func EnsureFs(ctx context.Context, inst *limatype.Instance) error {
baseDisk := filepath.Join(inst.Dir, filenames.BaseDisk)
baseDisk := filepath.Join(inst.Dir, filenames.BaseDiskLegacy)
if _, err := os.Stat(baseDisk); errors.Is(err, os.ErrNotExist) {
var ensuredBaseDisk bool
errs := make([]error, len(inst.Config.Images))
Expand Down
2 changes: 1 addition & 1 deletion pkg/driver/wsl2/vm_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func startVM(ctx context.Context, distroName string) error {

// initVM calls WSL to import a new VM specifically for Lima.
func initVM(ctx context.Context, instanceDir, distroName string) error {
baseDisk := filepath.Join(instanceDir, filenames.BaseDisk)
baseDisk := filepath.Join(instanceDir, filenames.BaseDiskLegacy)
logrus.Infof("Importing distro from %q to %q", baseDisk, instanceDir)
out, err := executil.RunUTF16leCommand([]string{
"wsl.exe",
Expand Down
95 changes: 70 additions & 25 deletions pkg/driverutil/disk.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,50 +12,95 @@ import (

"github.com/docker/go-units"
"github.com/lima-vm/go-qcow2reader/image"
"github.com/sirupsen/logrus"

"github.com/lima-vm/lima/v2/pkg/imgutil/proxyimgutil"
"github.com/lima-vm/lima/v2/pkg/iso9660util"
"github.com/lima-vm/lima/v2/pkg/limatype/filenames"
"github.com/lima-vm/lima/v2/pkg/osutil"
)

// EnsureDisk ensures that the diff disk exists with the specified size and format.
func EnsureDisk(ctx context.Context, instDir, diskSize string, diskImageFormat image.Type) error {
diffDisk := filepath.Join(instDir, filenames.DiffDisk)
if _, err := os.Stat(diffDisk); err == nil || !errors.Is(err, os.ErrNotExist) {
// disk is already ensured
return err
// MigrateDiskLayout creates symlinks from the current filenames (disk, iso) to
// the legacy filenames (diffdisk, basedisk) used by older Lima versions.
// The original files are left in place so older Lima versions can still use them.
func MigrateDiskLayout(instDir string) error {
diskPath := filepath.Join(instDir, filenames.Disk)
if osutil.FileExists(diskPath) {
return nil // already migrated or new instance
}

diskUtil := proxyimgutil.NewDiskUtil(ctx)
diffDiskPath := filepath.Join(instDir, filenames.DiffDiskLegacy)
if osutil.FileExists(diffDiskPath) {
logrus.Infof("Creating symlink %q -> %q", filenames.Disk, filenames.DiffDiskLegacy)
if err := os.Symlink(filenames.DiffDiskLegacy, diskPath); err != nil {
return fmt.Errorf("failed to symlink %q to %q: %w", filenames.Disk, filenames.DiffDiskLegacy, err)
}
}

baseDiskPath := filepath.Join(instDir, filenames.BaseDiskLegacy)
isoPath := filepath.Join(instDir, filenames.ISO)
if osutil.FileExists(baseDiskPath) && !osutil.FileExists(isoPath) {
isISO, err := iso9660util.IsISO9660(baseDiskPath)
if err != nil {
return err
}
if isISO {
logrus.Infof("Creating symlink %q -> %q", filenames.ISO, filenames.BaseDiskLegacy)
if err := os.Symlink(filenames.BaseDiskLegacy, isoPath); err != nil {
return fmt.Errorf("failed to symlink %q to %q: %w", filenames.ISO, filenames.BaseDiskLegacy, err)
}
}
// Non-ISO basedisk is a legacy qcow2 backing file; leave it for QEMU to resolve.
}

baseDisk := filepath.Join(instDir, filenames.BaseDisk)
return nil
}

diskSizeInBytes, _ := units.RAMInBytes(diskSize)
if diskSizeInBytes == 0 {
return nil
// EnsureDisk creates the VM disk from the downloaded image.
// For ISO images, it symlinks the ISO and creates an empty disk in the target format.
// For non-ISO images, it converts the image in place and symlinks disk to it.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just rename image to disk

func EnsureDisk(ctx context.Context, instDir, diskSize string, diskImageFormat image.Type) error {
diskPath := filepath.Join(instDir, filenames.Disk)
if _, err := os.Stat(diskPath); err == nil || !errors.Is(err, os.ErrNotExist) {
return err
}
isBaseDiskISO, err := iso9660util.IsISO9660(baseDisk)

imagePath := filepath.Join(instDir, filenames.Image)
isISO, err := iso9660util.IsISO9660(imagePath)
if err != nil {
return err
}
srcDisk := baseDisk
if isBaseDiskISO {
srcDisk = diffDisk

// Create an empty data volume for the diff disk
diffDiskF, err := os.Create(diffDisk)
diskSizeInBytes, _ := units.RAMInBytes(diskSize)
diskUtil := proxyimgutil.NewDiskUtil(ctx)

if isISO {
isoPath := filepath.Join(instDir, filenames.ISO)
if err := os.Symlink(filenames.Image, isoPath); err != nil {
return err
}
f, err := os.Create(diskPath)
if err != nil {
os.Remove(isoPath)
return err
}

if err = diffDiskF.Close(); err != nil {
if err := f.Close(); err != nil {
os.Remove(diskPath)
os.Remove(isoPath)
return err
}
if err := diskUtil.Convert(ctx, diskImageFormat, diskPath, diskPath, &diskSizeInBytes, false); err != nil {
os.Remove(diskPath)
os.Remove(isoPath)
return fmt.Errorf("failed to create disk %q: %w", diskPath, err)
}
} else {
if err := diskUtil.Convert(ctx, diskImageFormat, imagePath, imagePath, &diskSizeInBytes, false); err != nil {
return fmt.Errorf("failed to convert %q: %w", imagePath, err)
}
if err := os.Symlink(filenames.Image, diskPath); err != nil {
return err
}
}
// Check whether to use ASIF format

if err = diskUtil.Convert(ctx, diskImageFormat, srcDisk, diffDisk, &diskSizeInBytes, false); err != nil {
return fmt.Errorf("failed to convert %q to a disk %q: %w", srcDisk, diffDisk, err)
}
return err
return nil
}
Loading
Loading