Skip to content

Commit 957dfd2

Browse files
authored
Merge pull request #117 from balajiv113/disk
2 parents 23eeede + a275b82 commit 957dfd2

File tree

6 files changed

+132
-1
lines changed

6 files changed

+132
-1
lines changed

example/gui-linux/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ func createMainDiskImage(diskPath string) error {
114114
}
115115

116116
func createBlockDeviceConfiguration(diskPath string) (*vz.VirtioBlockDeviceConfiguration, error) {
117-
attachment, err := vz.NewDiskImageStorageDeviceAttachment(diskPath, false)
117+
attachment, err := vz.NewDiskImageStorageDeviceAttachmentWithCacheAndSync(diskPath, false, vz.DiskImageCachingModeAutomatic, vz.DiskImageSynchronizationModeFsync)
118118
if err != nil {
119119
return nil, fmt.Errorf("failed to create a new disk image storage device attachment: %w", err)
120120
}

osversion_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,10 @@ func TestAvailableVersion(t *testing.T) {
155155
"(*VirtualMachine).StartGraphicApplication": func() error {
156156
return (*VirtualMachine)(nil).StartGraphicApplication(0, 0)
157157
},
158+
"NewDiskImageStorageDeviceAttachmentWithCacheAndSync": func() error {
159+
_, err := NewDiskImageStorageDeviceAttachmentWithCacheAndSync("test", false, DiskImageCachingModeAutomatic, DiskImageSynchronizationModeFsync)
160+
return err
161+
},
158162
}
159163
for name, fn := range cases {
160164
t.Run(name, func(t *testing.T) {

storage.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ package vz
44
#cgo darwin CFLAGS: -mmacosx-version-min=11 -x objective-c -fno-objc-arc
55
#cgo darwin LDFLAGS: -lobjc -framework Foundation -framework Virtualization
66
# include "virtualization_11.h"
7+
# include "virtualization_12.h"
78
# include "virtualization_12_3.h"
89
# include "virtualization_13.h"
910
*/
@@ -41,6 +42,28 @@ type DiskImageStorageDeviceAttachment struct {
4142
*baseStorageDeviceAttachment
4243
}
4344

45+
// DiskImageCachingMode describes the disk image caching mode.
46+
//
47+
// see: https://developer.apple.com/documentation/virtualization/vzdiskimagecachingmode?language=objc
48+
type DiskImageCachingMode int
49+
50+
const (
51+
DiskImageCachingModeAutomatic DiskImageCachingMode = iota
52+
DiskImageCachingModeUncached
53+
DiskImageCachingModeCached
54+
)
55+
56+
// DiskImageSynchronizationMode describes the disk image synchronization mode.
57+
//
58+
// see: https://developer.apple.com/documentation/virtualization/vzdiskimagesynchronizationmode?language=objc
59+
type DiskImageSynchronizationMode int
60+
61+
const (
62+
DiskImageSynchronizationModeFull DiskImageSynchronizationMode = 1 + iota
63+
DiskImageSynchronizationModeFsync
64+
DiskImageSynchronizationModeNone
65+
)
66+
4467
// NewDiskImageStorageDeviceAttachment initialize the attachment from a local file path.
4568
// Returns error is not nil, assigned with the error if the initialization failed.
4669
//
@@ -79,6 +102,48 @@ func NewDiskImageStorageDeviceAttachment(diskPath string, readOnly bool) (*DiskI
79102
return attachment, nil
80103
}
81104

105+
// NewDiskImageStorageDeviceAttachmentWithCacheAndSync initialize the attachment from a local file path.
106+
// Returns error is not nil, assigned with the error if the initialization failed.
107+
//
108+
// - diskPath is local file URL to the disk image in RAW format.
109+
// - readOnly if YES, the device attachment is read-only, otherwise the device can write data to the disk image.
110+
// - cachingMode is one of the available DiskImageCachingMode options.
111+
// - syncMode is to define how the disk image synchronizes with the underlying storage when the guest operating system flushes data, described by one of the available DiskImageSynchronizationMode modes.
112+
//
113+
// This is only supported on macOS 12 and newer, error will
114+
// be returned on older versions.
115+
func NewDiskImageStorageDeviceAttachmentWithCacheAndSync(diskPath string, readOnly bool, cachingMode DiskImageCachingMode, syncMode DiskImageSynchronizationMode) (*DiskImageStorageDeviceAttachment, error) {
116+
if err := macOSAvailable(12); err != nil {
117+
return nil, err
118+
}
119+
if _, err := os.Stat(diskPath); err != nil {
120+
return nil, err
121+
}
122+
123+
nserrPtr := newNSErrorAsNil()
124+
125+
diskPathChar := charWithGoString(diskPath)
126+
defer diskPathChar.Free()
127+
attachment := &DiskImageStorageDeviceAttachment{
128+
pointer: objc.NewPointer(
129+
C.newVZDiskImageStorageDeviceAttachmentWithCacheAndSyncMode(
130+
diskPathChar.CString(),
131+
C.bool(readOnly),
132+
C.int(cachingMode),
133+
C.int(syncMode),
134+
&nserrPtr,
135+
),
136+
),
137+
}
138+
if err := newNSError(nserrPtr); err != nil {
139+
return nil, err
140+
}
141+
objc.SetFinalizer(attachment, func(self *DiskImageStorageDeviceAttachment) {
142+
objc.Release(self)
143+
})
144+
return attachment, nil
145+
}
146+
82147
// StorageDeviceConfiguration for a storage device configuration.
83148
type StorageDeviceConfiguration interface {
84149
objc.NSObject

storage_test.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,39 @@ func TestBlockDeviceIdentifier(t *testing.T) {
6262
t.Fatalf("want %q but got %q", want, got2)
6363
}
6464
}
65+
66+
func TestBlockDeviceWithCacheAndSyncMode(t *testing.T) {
67+
if vz.Available(12) {
68+
t.Skip("vz.NewDiskImageStorageDeviceAttachmentWithCacheAndSync is supported from macOS 12")
69+
}
70+
71+
container := newVirtualizationMachine(t,
72+
func(vmc *vz.VirtualMachineConfiguration) error {
73+
dir := t.TempDir()
74+
path := filepath.Join(dir, "disk.img")
75+
if err := vz.CreateDiskImage(path, 512); err != nil {
76+
t.Fatal(err)
77+
}
78+
79+
attachment, err := vz.NewDiskImageStorageDeviceAttachmentWithCacheAndSync(path, false, vz.DiskImageCachingModeAutomatic, vz.DiskImageSynchronizationModeFsync)
80+
if err != nil {
81+
t.Fatal(err)
82+
}
83+
config, err := vz.NewVirtioBlockDeviceConfiguration(attachment)
84+
if err != nil {
85+
t.Fatal(err)
86+
}
87+
vmc.SetStorageDevicesVirtualMachineConfiguration([]vz.StorageDeviceConfiguration{
88+
config,
89+
})
90+
return nil
91+
},
92+
)
93+
defer container.Close()
94+
95+
vm := container.VirtualMachine
96+
97+
if got := vm.State(); vz.VirtualMachineStateRunning != got {
98+
t.Fatalf("want state %v but got %v", vz.VirtualMachineStateRunning, got)
99+
}
100+
}

virtualization_12.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ void *newVZVirtioSoundDeviceHostInputStreamConfiguration(); // use in Go
2121
void *newVZVirtioSoundDeviceOutputStreamConfiguration();
2222
void *newVZVirtioSoundDeviceHostOutputStreamConfiguration(); // use in Go
2323

24+
void *newVZDiskImageStorageDeviceAttachmentWithCacheAndSyncMode(const char *diskPath, bool readOnly, int cacheMode, int syncMode, void **error);
2425
void *newVZUSBScreenCoordinatePointingDeviceConfiguration();
2526
void *newVZUSBKeyboardConfiguration();
2627
void *newVZVirtioSoundDeviceConfiguration();

virtualization_12.m

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,31 @@ void setStreamsVZVirtioSoundDeviceConfiguration(void *audioDeviceConfiguration,
210210
RAISE_UNSUPPORTED_MACOS_EXCEPTION();
211211
}
212212

213+
/*!
214+
@abstract Initialize the attachment from a local file url.
215+
@param diskPath Local file path to the disk image in RAW format.
216+
@param readOnly If YES, the device attachment is read-only, otherwise the device can write data to the disk image.
217+
@param cacheMode The caching mode from one of the available VZDiskImageCachingMode options.
218+
@param syncMode How the disk image synchronizes with the underlying storage when the guest operating system flushes data, described by one of the available VZDiskImageSynchronizationMode modes.
219+
@param error If not nil, assigned with the error if the initialization failed.
220+
@return A VZDiskImageStorageDeviceAttachment on success. Nil otherwise and the error parameter is populated if set.
221+
*/
222+
void *newVZDiskImageStorageDeviceAttachmentWithCacheAndSyncMode(const char *diskPath, bool readOnly, int cacheMode, int syncMode, void **error)
223+
{
224+
if (@available(macOS 12, *)) {
225+
NSString *diskPathNSString = [NSString stringWithUTF8String:diskPath];
226+
NSURL *diskURL = [NSURL fileURLWithPath:diskPathNSString];
227+
return [[VZDiskImageStorageDeviceAttachment alloc]
228+
initWithURL:diskURL
229+
readOnly:(BOOL)readOnly
230+
cachingMode:(VZDiskImageCachingMode)cacheMode
231+
synchronizationMode: (VZDiskImageSynchronizationMode)syncMode
232+
error:(NSError *_Nullable *_Nullable)error];
233+
}
234+
235+
RAISE_UNSUPPORTED_MACOS_EXCEPTION();
236+
}
237+
213238
/*!
214239
@abstract Initialize the VZSharedDirectory from the directory path and read only option.
215240
@param dirPath

0 commit comments

Comments
 (0)