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
3 changes: 2 additions & 1 deletion pkg/driver/krunkit/krunkit_darwin_arm64.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"strconv"

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

"github.com/lima-vm/lima/v2/pkg/driver/vz"
Expand Down Expand Up @@ -65,7 +66,7 @@ func Cmdline(inst *limatype.Instance) (*exec.Cmd, error) {
}
extraDiskPath := filepath.Join(disk.Dir, filenames.DataDisk)
logrus.Infof("Mounting disk %q on %q", disk.Name, disk.MountPoint)
if cerr := diskUtil.ConvertToRaw(ctx, extraDiskPath, extraDiskPath, nil, true); cerr != nil {
if cerr := diskUtil.Convert(ctx, raw.Type, extraDiskPath, extraDiskPath, nil, true); cerr != nil {
return nil, fmt.Errorf("failed to convert extra disk %q to raw: %w", extraDiskPath, cerr)
}
args = append(args, "--device", fmt.Sprintf("virtio-blk,path=%s,format=raw", extraDiskPath))
Expand Down
3 changes: 2 additions & 1 deletion pkg/driver/krunkit/krunkit_driver_darwin_arm64.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"time"

"github.com/coreos/go-semver/semver"
"github.com/lima-vm/go-qcow2reader/image/raw"
"github.com/sirupsen/logrus"

"github.com/lima-vm/lima/v2/pkg/driver"
Expand Down Expand Up @@ -60,7 +61,7 @@ func (l *LimaKrunkitDriver) Configure(inst *limatype.Instance) *driver.Configure

func (l *LimaKrunkitDriver) CreateDisk(ctx context.Context) error {
// Krunkit also supports qcow2 disks but raw is faster to create and use.
return driverutil.EnsureDiskRaw(ctx, l.Instance)
return driverutil.EnsureDisk(ctx, l.Instance.Dir, *l.Instance.Config.Disk, raw.Type)
}

func (l *LimaKrunkitDriver) Start(ctx context.Context) (chan error, error) {
Expand Down
10 changes: 7 additions & 3 deletions pkg/driver/vz/vm_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"os"
"path/filepath"
"runtime"
"slices"
"strconv"
"sync"
"syscall"
Expand All @@ -22,6 +23,8 @@ import (
"github.com/coreos/go-semver/semver"
"github.com/docker/go-units"
"github.com/lima-vm/go-qcow2reader"
"github.com/lima-vm/go-qcow2reader/image"
"github.com/lima-vm/go-qcow2reader/image/asif"
"github.com/lima-vm/go-qcow2reader/image/raw"
"github.com/sirupsen/logrus"

Expand Down Expand Up @@ -451,8 +454,9 @@ func validateDiskFormat(diskPath string) error {
if err != nil {
return fmt.Errorf("failed to detect the format of %q: %w", diskPath, err)
}
if t := img.Type(); t != raw.Type {
return fmt.Errorf("expected the format of %q to be %q, got %q", diskPath, raw.Type, t)
supportedDiskTypes := []image.Type{raw.Type, asif.Type}
if t := img.Type(); !slices.Contains(supportedDiskTypes, t) {
return fmt.Errorf("expected the format of %q to be one of %v, got %q", diskPath, supportedDiskTypes, t)
}
// TODO: ensure that the disk is formatted with GPT or ISO9660
return nil
Expand Down Expand Up @@ -516,7 +520,7 @@ func attachDisks(ctx context.Context, inst *limatype.Instance, vmConfig *vz.Virt
// ConvertToRaw is a NOP if no conversion is needed
logrus.Debugf("Converting extra disk %q to a raw disk (if it is not a raw)", extraDiskPath)

if err = diskUtil.ConvertToRaw(ctx, extraDiskPath, extraDiskPath, nil, true); err != nil {
if err = diskUtil.Convert(ctx, raw.Type, extraDiskPath, extraDiskPath, nil, true); err != nil {
return fmt.Errorf("failed to convert extra disk %q to a raw disk: %w", extraDiskPath, err)
}
extraDiskPathAttachment, err := vz.NewDiskImageStorageDeviceAttachmentWithCacheAndSync(extraDiskPath, false, diskImageCachingMode, vz.DiskImageSynchronizationModeFsync)
Expand Down
37 changes: 31 additions & 6 deletions pkg/driver/vz/vz_driver_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ import (

"github.com/Code-Hex/vz/v3"
"github.com/coreos/go-semver/semver"
"github.com/lima-vm/go-qcow2reader/image"
"github.com/lima-vm/go-qcow2reader/image/asif"
"github.com/lima-vm/go-qcow2reader/image/raw"
"github.com/sirupsen/logrus"

"github.com/lima-vm/lima/v2/pkg/driver"
Expand Down Expand Up @@ -75,11 +78,12 @@ const Enabled = true
type LimaVzDriver struct {
Instance *limatype.Instance

SSHLocalPort int
vSockPort int
virtioPort string
rosettaEnabled bool
rosettaBinFmt bool
SSHLocalPort int
vSockPort int
virtioPort string
rosettaEnabled bool
rosettaBinFmt bool
diskImageFormat image.Type

machine *virtualMachineWrapper
waitSSHLocalPortAccessible <-chan any
Expand Down Expand Up @@ -125,6 +129,11 @@ func (l *LimaVzDriver) Configure(inst *limatype.Instance) *driver.ConfiguredDriv
if vzOpts.Rosetta.BinFmt != nil {
l.rosettaBinFmt = *vzOpts.Rosetta.BinFmt
}
if vzOpts.DiskImageFormat != nil {
l.diskImageFormat = *vzOpts.DiskImageFormat
} else {
l.diskImageFormat = raw.Type
}

return &driver.ConfiguredDriver{
Driver: l,
Expand Down Expand Up @@ -161,6 +170,9 @@ func (l *LimaVzDriver) FillConfig(ctx context.Context, cfg *limatype.LimaYAML, _
if vzOpts.Rosetta.BinFmt == nil {
vzOpts.Rosetta.BinFmt = ptr.Of(false)
}
if vzOpts.DiskImageFormat == nil {
vzOpts.DiskImageFormat = ptr.Of(raw.Type)
}

var opts any
if err := limayaml.Convert(vzOpts, &opts, ""); err != nil {
Expand Down Expand Up @@ -286,6 +298,19 @@ func validateConfig(_ context.Context, cfg *limatype.LimaYAML) error {
default:
logrus.Warnf("field `video.display` must be \"vz\", \"default\", or \"none\" for VZ driver , got %q", videoDisplay)
}
var vzOpts limatype.VZOpts
if err := limayaml.Convert(cfg.VMOpts[limatype.VZ], &vzOpts, "vmOpts.vz"); err != nil {
logrus.WithError(err).Warnf("Couldn't convert %q", cfg.VMOpts[limatype.VZ])
}
switch *vzOpts.DiskImageFormat {
case raw.Type:
case asif.Type:
if macOSProductVersion.LessThan(*semver.New("26.0.0")) {
return fmt.Errorf("vmOpts.vz.diskImageFormat=%q requires macOS 26 or higher to run, got %q", asif.Type, macOSProductVersion)
}
default:
return fmt.Errorf("field `vmOpts.vz.diskImageFormat` must be %q or %q, got %q", raw.Type, asif.Type, *vzOpts.DiskImageFormat)
}
return nil
}

Expand All @@ -295,7 +320,7 @@ func (l *LimaVzDriver) Create(_ context.Context) error {
}

func (l *LimaVzDriver) CreateDisk(ctx context.Context) error {
return driverutil.EnsureDiskRaw(ctx, l.Instance)
return driverutil.EnsureDisk(ctx, l.Instance.Dir, *l.Instance.Config.Disk, l.diskImageFormat)
}

func (l *LimaVzDriver) Start(ctx context.Context) (chan error, error) {
Expand Down
19 changes: 11 additions & 8 deletions pkg/driverutil/disk.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,27 @@ import (
"path/filepath"

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

"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"
)

func EnsureDiskRaw(ctx context.Context, inst *limatype.Instance) error {
diffDisk := filepath.Join(inst.Dir, filenames.DiffDisk)
// 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
}

diskUtil := proxyimgutil.NewDiskUtil(ctx)

baseDisk := filepath.Join(inst.Dir, filenames.BaseDisk)
baseDisk := filepath.Join(instDir, filenames.BaseDisk)

diskSize, _ := units.RAMInBytes(*inst.Config.Disk)
if diskSize == 0 {
diskSizeInBytes, _ := units.RAMInBytes(diskSize)
if diskSizeInBytes == 0 {
return nil
}
isBaseDiskISO, err := iso9660util.IsISO9660(baseDisk)
Expand All @@ -51,8 +52,10 @@ func EnsureDiskRaw(ctx context.Context, inst *limatype.Instance) error {
}
return diffDiskF.Close()
}
if err = diskUtil.ConvertToRaw(ctx, baseDisk, diffDisk, &diskSize, false); err != nil {
return fmt.Errorf("failed to convert %q to a raw disk %q: %w", baseDisk, diffDisk, err)
// Check whether to use ASIF format

if err = diskUtil.Convert(ctx, diskImageFormat, baseDisk, diffDisk, &diskSizeInBytes, false); err != nil {
return fmt.Errorf("failed to convert %q to a disk %q: %w", baseDisk, diffDisk, err)
}
return err
}
6 changes: 4 additions & 2 deletions pkg/imgutil/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ package imgutil
import (
"context"
"os"

"github.com/lima-vm/go-qcow2reader/image"
)

// ImageDiskManager defines the common operations for disk image utilities.
Expand All @@ -16,8 +18,8 @@ type ImageDiskManager interface {
// ResizeDisk resizes an existing disk image to the specified size.
ResizeDisk(ctx context.Context, disk string, size int64) error

// ConvertToRaw converts a disk image to raw format.
ConvertToRaw(ctx context.Context, source, dest string, size *int64, allowSourceWithBackingFile bool) error
// Convert converts a disk image to the specified format.
Convert(ctx context.Context, imageType image.Type, source, dest string, size *int64, allowSourceWithBackingFile bool) error

// MakeSparse makes a file sparse, starting from the specified offset.
MakeSparse(ctx context.Context, f *os.File, offset int64) error
Expand Down
51 changes: 51 additions & 0 deletions pkg/imgutil/nativeimgutil/asifutil/asif_darwin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// SPDX-FileCopyrightText: Copyright The Lima Authors
// SPDX-License-Identifier: Apache-2.0

package asifutil

import (
"context"
"fmt"
"os"
"os/exec"
"strings"
)

// NewAttachedASIF creates a new ASIF image file at the specified path with the given size
// and attaches it, returning the attached device path and an open file handle.
// The caller is responsible for detaching the ASIF image device when done.
func NewAttachedASIF(path string, size int64) (string, *os.File, error) {
createArgs := []string{"image", "create", "blank", "--fs", "none", "--format", "ASIF", "--size", fmt.Sprintf("%d", size), path}
if err := exec.CommandContext(context.Background(), "diskutil", createArgs...).Run(); err != nil {
return "", nil, fmt.Errorf("failed to create ASIF image %q: %w", path, err)
}
attachArgs := []string{"image", "attach", "--noMount", path}
out, err := exec.CommandContext(context.Background(), "diskutil", attachArgs...).Output()
if err != nil {
return "", nil, fmt.Errorf("failed to attach ASIF image %q: %w", path, err)
}
devicePath := strings.TrimSpace(string(out))
f, err := os.OpenFile(devicePath, os.O_RDWR, 0o644)
if err != nil {
_ = DetachASIF(devicePath)
return "", nil, fmt.Errorf("failed to open ASIF device %q: %w", devicePath, err)
}
return devicePath, f, err
}

// DetachASIF detaches the ASIF image device at the specified path.
func DetachASIF(devicePath string) error {
if output, err := exec.CommandContext(context.Background(), "hdiutil", "detach", devicePath).CombinedOutput(); err != nil {
return fmt.Errorf("failed to detach ASIF image %q: %w: %s", devicePath, err, output)
}
return nil
}

// ResizeASIF resizes the ASIF image at the specified path to the given size.
func ResizeASIF(path string, size int64) error {
resizeArgs := []string{"image", "resize", "--size", fmt.Sprintf("%d", size), path}
if output, err := exec.CommandContext(context.Background(), "diskutil", resizeArgs...).CombinedOutput(); err != nil {
return fmt.Errorf("failed to resize ASIF image %q: %w: %s", path, err, output)
}
return nil
}
25 changes: 25 additions & 0 deletions pkg/imgutil/nativeimgutil/asifutil/asif_others.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//go:build !darwin

// SPDX-FileCopyrightText: Copyright The Lima Authors
// SPDX-License-Identifier: Apache-2.0

package asifutil

import (
"errors"
"os"
)

var ErrASIFNotSupported = errors.New("ASIF is only supported on macOS")

func NewAttachedASIF(_ string, _ int64) (string, *os.File, error) {
return "", nil, ErrASIFNotSupported
}

func DetachASIF(_ string) error {
return ErrASIFNotSupported
}

func ResizeASIF(_ string, _ int64) error {
return ErrASIFNotSupported
}
3 changes: 2 additions & 1 deletion pkg/imgutil/nativeimgutil/fuzz_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"path/filepath"
"testing"

"github.com/lima-vm/go-qcow2reader/image/raw"
"gotest.tools/v3/assert"
)

Expand All @@ -17,6 +18,6 @@ func FuzzConvertToRaw(f *testing.F) {
destPath := filepath.Join(t.TempDir(), "dest.img")
err := os.WriteFile(srcPath, imgData, 0o600)
assert.NilError(t, err)
_ = convertToRaw(srcPath, destPath, &size, withBacking)
_ = convertTo(raw.Type, srcPath, destPath, &size, withBacking)
})
}
Loading
Loading