Skip to content

Commit

Permalink
limactl disk: Do not use qemu-img for raw disks
Browse files Browse the repository at this point in the history
Fix `limactl disk create` and `limactl disk resize` to use nativeimgutil
for creating and resizing disks using raw format.

There are special cases (using direct I/O on certain file systems) when
creating a raw image should be done with qemu-img, but these are not
relevant to lima on macOS.

With this change we have no dependency on qemu when using VZ instance.

This change does not fix the issue of default "qcow2" disk format.
Users must specify the disk format when creating additional disks for VZ
instance:

    limactl disk create --format raw

Unfinished:
- Needs tests for nativeimgutil and disk command

Fixes: #2853
Signed-off-by: Nir Soffer <[email protected]>
  • Loading branch information
nirs committed Jan 30, 2025
1 parent 77204d8 commit be8ad7a
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 4 deletions.
19 changes: 17 additions & 2 deletions cmd/limactl/disk.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"text/tabwriter"

"github.com/docker/go-units"
"github.com/lima-vm/lima/pkg/nativeimgutil"
"github.com/lima-vm/lima/pkg/qemu"
"github.com/lima-vm/lima/pkg/store"
"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -101,7 +102,13 @@ func diskCreateAction(cmd *cobra.Command, args []string) error {
return err
}

if err := qemu.CreateDataDisk(diskDir, format, int(diskSize)); err != nil {
// qemu may not be available, use it only if needed.
if format == "raw" {
err = nativeimgutil.CreateRawDataDisk(diskDir, int(diskSize))
} else {
err = qemu.CreateDataDisk(diskDir, format, int(diskSize))
}
if err != nil {
rerr := os.RemoveAll(diskDir)
if rerr != nil {
err = errors.Join(err, fmt.Errorf("failed to remove a directory %q: %w", diskDir, rerr))
Expand Down Expand Up @@ -390,9 +397,17 @@ func diskResizeAction(cmd *cobra.Command, args []string) error {
}
}
}
if err := qemu.ResizeDataDisk(disk.Dir, disk.Format, int(diskSize)); err != nil {

// qemu may not be available, use it only if needed.
if disk.Format == "raw" {
err = nativeimgutil.ResizeRawDataDisk(disk.Dir, int(diskSize))
} else {
err = qemu.ResizeDataDisk(disk.Dir, disk.Format, int(diskSize))
}
if err != nil {
return fmt.Errorf("failed to resize disk %q: %w", diskName, err)
}

logrus.Infof("Resized disk %q (%q)", diskName, disk.Dir)
return nil
}
Expand Down
27 changes: 25 additions & 2 deletions pkg/nativeimgutil/nativeimgutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,44 @@
package nativeimgutil

import (
"errors"
"fmt"
"io"
"io/fs"
"os"
"path/filepath"

"github.com/containerd/continuity/fs"
containerdfs "github.com/containerd/continuity/fs"
"github.com/docker/go-units"
"github.com/lima-vm/go-qcow2reader"
"github.com/lima-vm/go-qcow2reader/convert"
"github.com/lima-vm/go-qcow2reader/image/qcow2"
"github.com/lima-vm/go-qcow2reader/image/raw"
"github.com/lima-vm/lima/pkg/progressbar"
"github.com/lima-vm/lima/pkg/store/filenames"
"github.com/sirupsen/logrus"
)

// CreateRawDataDisk creates an empty raw data disk.
func CreateRawDataDisk(dir string, size int) error {
dataDisk := filepath.Join(dir, filenames.DataDisk)
if _, err := os.Stat(dataDisk); err == nil || !errors.Is(err, fs.ErrNotExist) {
return err
}
f, err := os.Create(dataDisk)
if err != nil {
return err
}
defer f.Close()
return f.Truncate(int64(size))
}

// ResizeRawDataDisk resizes a raw data disk.
func ResizeRawDataDisk(dir string, size int) error {
dataDisk := filepath.Join(dir, filenames.DataDisk)
return os.Truncate(dataDisk, int64(size))
}

// ConvertToRaw converts a source disk into a raw disk.
// source and dest may be same.
// ConvertToRaw is a NOP if source == dest, and no resizing is needed.
Expand Down Expand Up @@ -106,7 +129,7 @@ func ConvertToRaw(source, dest string, size *int64, allowSourceWithBackingFile b
func convertRawToRaw(source, dest string, size *int64) error {
if source != dest {
// continuity attempts clonefile
if err := fs.CopyFile(dest, source); err != nil {
if err := containerdfs.CopyFile(dest, source); err != nil {
return fmt.Errorf("failed to copy %q into %q: %w", source, dest, err)
}
}
Expand Down

0 comments on commit be8ad7a

Please sign in to comment.