mirror of
https://github.com/microsoft/WSL.git
synced 2025-12-10 00:44:55 -06:00
Implement WSLA API to unmount & detach disks (#13364)
* Implement WSLA API to unmount & detach disks * Add WSL2_TEST_ONLY(); * Fix wslg path
This commit is contained in:
parent
3451e8213d
commit
28bcfe39d6
@ -427,6 +427,18 @@ void HandleMessageImpl(wsl::shared::SocketChannel& Channel, const LSW_SIGNAL& Me
|
|||||||
Channel.SendResultMessage(result < 0 ? errno : 0);
|
Channel.SendResultMessage(result < 0 ? errno : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HandleMessageImpl(wsl::shared::SocketChannel& Channel, const LSW_UNMOUNT& Message, const gsl::span<gsl::byte>& Buffer)
|
||||||
|
{
|
||||||
|
Channel.SendResultMessage<int32_t>(umount(Message.Buffer) == 0 ? 0 : errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandleMessageImpl(wsl::shared::SocketChannel& Channel, const LSW_DETACH& Message, const gsl::span<gsl::byte>& Buffer)
|
||||||
|
{
|
||||||
|
sync();
|
||||||
|
|
||||||
|
Channel.SendResultMessage<int32_t>(DetachScsiDisk(Message.Lun));
|
||||||
|
}
|
||||||
|
|
||||||
template <typename TMessage, typename... Args>
|
template <typename TMessage, typename... Args>
|
||||||
void HandleMessage(wsl::shared::SocketChannel& Channel, LX_MESSAGE_TYPE Type, const gsl::span<gsl::byte>& Buffer)
|
void HandleMessage(wsl::shared::SocketChannel& Channel, LX_MESSAGE_TYPE Type, const gsl::span<gsl::byte>& Buffer)
|
||||||
{
|
{
|
||||||
@ -461,7 +473,7 @@ void ProcessMessage(wsl::shared::SocketChannel& Channel, LX_MESSAGE_TYPE Type, c
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
HandleMessage<LSW_GET_DISK, LSW_MOUNT, LSW_EXEC, LSW_FORK, LSW_CONNECT, LSW_WAITPID, LSW_SIGNAL, LSW_TTY_RELAY, LSW_PORT_RELAY>(
|
HandleMessage<LSW_GET_DISK, LSW_MOUNT, LSW_EXEC, LSW_FORK, LSW_CONNECT, LSW_WAITPID, LSW_SIGNAL, LSW_TTY_RELAY, LSW_PORT_RELAY, LSW_UNMOUNT, LSW_DETACH>(
|
||||||
Channel, Type, Buffer);
|
Channel, Type, Buffer);
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
|
|||||||
@ -384,6 +384,8 @@ typedef enum _LX_MESSAGE_TYPE
|
|||||||
LxMessageLswMapPort,
|
LxMessageLswMapPort,
|
||||||
LxMessageLswConnectRelay,
|
LxMessageLswConnectRelay,
|
||||||
LxMessageLswPortRelay,
|
LxMessageLswPortRelay,
|
||||||
|
LxMessageLswUnmount,
|
||||||
|
LxMessageLswDetach,
|
||||||
} LX_MESSAGE_TYPE,
|
} LX_MESSAGE_TYPE,
|
||||||
*PLX_MESSAGE_TYPE;
|
*PLX_MESSAGE_TYPE;
|
||||||
|
|
||||||
@ -488,6 +490,8 @@ inline auto ToString(LX_MESSAGE_TYPE messageType)
|
|||||||
X(LxMessageLswMapPort)
|
X(LxMessageLswMapPort)
|
||||||
X(LxMessageLswConnectRelay)
|
X(LxMessageLswConnectRelay)
|
||||||
X(LxMessageLswPortRelay)
|
X(LxMessageLswPortRelay)
|
||||||
|
X(LxMessageLswUnmount)
|
||||||
|
X(LxMessageLswDetach)
|
||||||
default:
|
default:
|
||||||
return "<unexpected LX_MESSAGE_TYPE>";
|
return "<unexpected LX_MESSAGE_TYPE>";
|
||||||
}
|
}
|
||||||
@ -1760,6 +1764,31 @@ struct LSW_PORT_RELAY
|
|||||||
PRETTY_PRINT(FIELD(Header));
|
PRETTY_PRINT(FIELD(Header));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct LSW_UNMOUNT
|
||||||
|
{
|
||||||
|
static inline auto Type = LxMessageLswUnmount;
|
||||||
|
using TResponse = RESULT_MESSAGE<int32_t>;
|
||||||
|
|
||||||
|
DECLARE_MESSAGE_CTOR(LSW_UNMOUNT);
|
||||||
|
MESSAGE_HEADER Header;
|
||||||
|
|
||||||
|
char Buffer[];
|
||||||
|
|
||||||
|
PRETTY_PRINT(FIELD(Header), FIELD(Buffer));
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LSW_DETACH
|
||||||
|
{
|
||||||
|
static inline auto Type = LxMessageLswDetach;
|
||||||
|
using TResponse = RESULT_MESSAGE<int32_t>;
|
||||||
|
|
||||||
|
DECLARE_MESSAGE_CTOR(LSW_DETACH);
|
||||||
|
MESSAGE_HEADER Header;
|
||||||
|
unsigned int Lun;
|
||||||
|
|
||||||
|
PRETTY_PRINT(FIELD(Header), FIELD(Lun));
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct _LX_MINI_INIT_IMPORT_RESULT
|
typedef struct _LX_MINI_INIT_IMPORT_RESULT
|
||||||
{
|
{
|
||||||
static inline auto Type = LxMiniInitMessageImportResult;
|
static inline auto Type = LxMiniInitMessageImportResult;
|
||||||
|
|||||||
@ -111,9 +111,9 @@ CATCH_RETURN();
|
|||||||
HRESULT WslAttachDisk(LSWVirtualMachineHandle VirtualMachine, const DiskAttachSettings* Settings, AttachedDiskInformation* AttachedDisk)
|
HRESULT WslAttachDisk(LSWVirtualMachineHandle VirtualMachine, const DiskAttachSettings* Settings, AttachedDiskInformation* AttachedDisk)
|
||||||
{
|
{
|
||||||
wil::unique_cotaskmem_ansistring device;
|
wil::unique_cotaskmem_ansistring device;
|
||||||
RETURN_IF_FAILED(reinterpret_cast<ILSWVirtualMachine*>(VirtualMachine)->AttachDisk(Settings->WindowsPath, Settings->ReadOnly, &device));
|
RETURN_IF_FAILED(reinterpret_cast<ILSWVirtualMachine*>(VirtualMachine)
|
||||||
|
->AttachDisk(Settings->WindowsPath, Settings->ReadOnly, &device, &AttachedDisk->ScsiLun));
|
||||||
|
|
||||||
// TODO: wire LUN
|
|
||||||
auto deviceSize = strlen(device.get());
|
auto deviceSize = strlen(device.get());
|
||||||
WI_VERIFY(deviceSize < sizeof(AttachedDiskInformation::Device));
|
WI_VERIFY(deviceSize < sizeof(AttachedDiskInformation::Device));
|
||||||
|
|
||||||
@ -285,6 +285,15 @@ try
|
|||||||
}
|
}
|
||||||
CATCH_RETURN();
|
CATCH_RETURN();
|
||||||
|
|
||||||
|
HRESULT WslUnmount(LSWVirtualMachineHandle VirtualMachine, const char* Path)
|
||||||
|
{
|
||||||
|
return reinterpret_cast<ILSWVirtualMachine*>(VirtualMachine)->Unmount(Path);
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT WslDetachDisk(LSWVirtualMachineHandle VirtualMachine, ULONG Lun)
|
||||||
|
{
|
||||||
|
return reinterpret_cast<ILSWVirtualMachine*>(VirtualMachine)->DetachDisk(Lun);
|
||||||
|
}
|
||||||
EXTERN_C BOOL STDAPICALLTYPE DllMain(_In_ HINSTANCE Instance, _In_ DWORD Reason, _In_opt_ LPVOID Reserved)
|
EXTERN_C BOOL STDAPICALLTYPE DllMain(_In_ HINSTANCE Instance, _In_ DWORD Reason, _In_opt_ LPVOID Reserved)
|
||||||
{
|
{
|
||||||
wil::DLLMain(Instance, Reason, Reserved);
|
wil::DLLMain(Instance, Reason, Reserved);
|
||||||
|
|||||||
@ -179,6 +179,10 @@ HRESULT WslMapPort(LSWVirtualMachineHandle VirtualMachine, const struct PortMapp
|
|||||||
|
|
||||||
HRESULT WslUnmapPort(LSWVirtualMachineHandle VirtualMachine, const struct PortMappingSettings* Settings);
|
HRESULT WslUnmapPort(LSWVirtualMachineHandle VirtualMachine, const struct PortMappingSettings* Settings);
|
||||||
|
|
||||||
|
HRESULT WslUnmount(LSWVirtualMachineHandle VirtualMachine, const char* Path);
|
||||||
|
|
||||||
|
HRESULT WslDetachDisk(LSWVirtualMachineHandle VirtualMachine, ULONG Lun);
|
||||||
|
|
||||||
enum WslInstallComponent
|
enum WslInstallComponent
|
||||||
{
|
{
|
||||||
WslInstallComponentNone = 0,
|
WslInstallComponentNone = 0,
|
||||||
|
|||||||
@ -14,6 +14,8 @@ EXPORTS
|
|||||||
WslLaunchDebugShell
|
WslLaunchDebugShell
|
||||||
WslMapPort
|
WslMapPort
|
||||||
WslUnmapPort
|
WslUnmapPort
|
||||||
|
WslDetachDisk
|
||||||
|
WslUnmount
|
||||||
WslQueryMissingComponents
|
WslQueryMissingComponents
|
||||||
WslInstallComponents
|
WslInstallComponents
|
||||||
WslSetPackageUrl
|
WslSetPackageUrl
|
||||||
|
|||||||
@ -331,7 +331,7 @@ void LSWVirtualMachine::OnExit(_In_ const HCS_EVENT* Event)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT LSWVirtualMachine::AttachDisk(_In_ PCWSTR Path, _In_ BOOL ReadOnly, _Out_ LPSTR* Device)
|
HRESULT LSWVirtualMachine::AttachDisk(_In_ PCWSTR Path, _In_ BOOL ReadOnly, _Out_ LPSTR* Device, _Out_ ULONG* Lun)
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
*Device = nullptr;
|
*Device = nullptr;
|
||||||
@ -345,35 +345,35 @@ try
|
|||||||
wsl::windows::common::hcs::GrantVmAccess(m_vmIdString.c_str(), Path);
|
wsl::windows::common::hcs::GrantVmAccess(m_vmIdString.c_str(), Path);
|
||||||
}
|
}
|
||||||
|
|
||||||
ULONG lun = 0;
|
*Lun = 0;
|
||||||
while (m_attachedDisks.find(lun) != m_attachedDisks.end())
|
while (m_attachedDisks.find(*Lun) != m_attachedDisks.end())
|
||||||
{
|
{
|
||||||
lun++;
|
(*Lun)++;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool vhdAdded = false;
|
bool vhdAdded = false;
|
||||||
auto cleanup = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [&]() {
|
auto cleanup = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [&]() {
|
||||||
if (vhdAdded)
|
if (vhdAdded)
|
||||||
{
|
{
|
||||||
wsl::windows::common::hcs::RemoveScsiDisk(m_computeSystem.get(), lun);
|
wsl::windows::common::hcs::RemoveScsiDisk(m_computeSystem.get(), *Lun);
|
||||||
}
|
}
|
||||||
|
|
||||||
wsl::windows::common::hcs::RevokeVmAccess(m_vmIdString.c_str(), Path);
|
wsl::windows::common::hcs::RevokeVmAccess(m_vmIdString.c_str(), Path);
|
||||||
});
|
});
|
||||||
|
|
||||||
wsl::windows::common::hcs::AddVhd(m_computeSystem.get(), Path, lun, ReadOnly);
|
wsl::windows::common::hcs::AddVhd(m_computeSystem.get(), Path, *Lun, ReadOnly);
|
||||||
vhdAdded = true;
|
vhdAdded = true;
|
||||||
|
|
||||||
LSW_GET_DISK message{};
|
LSW_GET_DISK message{};
|
||||||
message.Header.MessageSize = sizeof(message);
|
message.Header.MessageSize = sizeof(message);
|
||||||
message.Header.MessageType = LSW_GET_DISK::Type;
|
message.Header.MessageType = LSW_GET_DISK::Type;
|
||||||
message.ScsiLun = lun;
|
message.ScsiLun = *Lun;
|
||||||
const auto& response = m_initChannel.Transaction(message);
|
const auto& response = m_initChannel.Transaction(message);
|
||||||
|
|
||||||
THROW_HR_IF_MSG(E_FAIL, response.Result != 0, "Failed to attach disk, init returned: %lu", response.Result);
|
THROW_HR_IF_MSG(E_FAIL, response.Result != 0, "Failed to attach disk, init returned: %lu", response.Result);
|
||||||
|
|
||||||
cleanup.release();
|
cleanup.release();
|
||||||
m_attachedDisks.emplace(lun, AttachedDisk{Path, response.Buffer});
|
m_attachedDisks.emplace(*Lun, AttachedDisk{Path, response.Buffer});
|
||||||
|
|
||||||
*Device = wil::make_unique_ansistring<wil::unique_cotaskmem_ansistring>(response.Buffer).release();
|
*Device = wil::make_unique_ansistring<wil::unique_cotaskmem_ansistring>(response.Buffer).release();
|
||||||
});
|
});
|
||||||
@ -431,6 +431,49 @@ try
|
|||||||
}
|
}
|
||||||
CATCH_RETURN();
|
CATCH_RETURN();
|
||||||
|
|
||||||
|
HRESULT LSWVirtualMachine::Unmount(_In_ const char* Path)
|
||||||
|
try
|
||||||
|
{
|
||||||
|
auto [pid, _, subChannel] = Fork(LSW_FORK::Thread);
|
||||||
|
|
||||||
|
wsl::shared::MessageWriter<LSW_UNMOUNT> message;
|
||||||
|
message.WriteString(Path);
|
||||||
|
|
||||||
|
const auto& response = subChannel.Transaction<LSW_UNMOUNT>(message.Span());
|
||||||
|
|
||||||
|
// TODO: Return errno to caller
|
||||||
|
THROW_HR_IF(E_FAIL, response.Result != 0);
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
CATCH_RETURN()
|
||||||
|
|
||||||
|
HRESULT LSWVirtualMachine::DetachDisk(_In_ ULONG Lun)
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::lock_guard lock{m_lock};
|
||||||
|
|
||||||
|
// Find the disk
|
||||||
|
auto it = m_attachedDisks.find(Lun);
|
||||||
|
RETURN_HR_IF(HRESULT_FROM_WIN32(ERROR_NOT_FOUND), it == m_attachedDisks.end());
|
||||||
|
|
||||||
|
// Detach it from the guest
|
||||||
|
LSW_DETACH message;
|
||||||
|
message.Lun = Lun;
|
||||||
|
const auto& response = m_initChannel.Transaction(message);
|
||||||
|
|
||||||
|
// TODO: Return errno to caller
|
||||||
|
THROW_HR_IF(E_FAIL, response.Result != 0);
|
||||||
|
|
||||||
|
// Remove it from the VM
|
||||||
|
m_attachedDisks.erase(it);
|
||||||
|
|
||||||
|
hcs::RemoveScsiDisk(m_computeSystem.get(), Lun);
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
CATCH_RETURN()
|
||||||
|
|
||||||
std::tuple<int32_t, int32_t, wsl::shared::SocketChannel> LSWVirtualMachine::Fork(enum LSW_FORK::ForkType Type)
|
std::tuple<int32_t, int32_t, wsl::shared::SocketChannel> LSWVirtualMachine::Fork(enum LSW_FORK::ForkType Type)
|
||||||
{
|
{
|
||||||
std::lock_guard lock{m_lock};
|
std::lock_guard lock{m_lock};
|
||||||
|
|||||||
@ -28,7 +28,7 @@ public:
|
|||||||
|
|
||||||
void Start();
|
void Start();
|
||||||
|
|
||||||
IFACEMETHOD(AttachDisk(_In_ PCWSTR Path, _In_ BOOL ReadOnly, _Out_ LPSTR* Device)) override;
|
IFACEMETHOD(AttachDisk(_In_ PCWSTR Path, _In_ BOOL ReadOnly, _Out_ LPSTR* Device, _Out_ ULONG* Lun)) override;
|
||||||
IFACEMETHOD(Mount(_In_ LPCSTR Source, _In_ LPCSTR Target, _In_ LPCSTR Type, _In_ LPCSTR Options, _In_ ULONG Flags)) override;
|
IFACEMETHOD(Mount(_In_ LPCSTR Source, _In_ LPCSTR Target, _In_ LPCSTR Type, _In_ LPCSTR Options, _In_ ULONG Flags)) override;
|
||||||
IFACEMETHOD(CreateLinuxProcess(
|
IFACEMETHOD(CreateLinuxProcess(
|
||||||
_In_ const LSW_CREATE_PROCESS_OPTIONS* Options, _In_ ULONG FdCount, _In_ LSW_PROCESS_FD* Fd, _Out_ HANDLE* Handles, _Out_ LSW_CREATE_PROCESS_RESULT* Result)) override;
|
_In_ const LSW_CREATE_PROCESS_OPTIONS* Options, _In_ ULONG FdCount, _In_ LSW_PROCESS_FD* Fd, _Out_ HANDLE* Handles, _Out_ LSW_CREATE_PROCESS_RESULT* Result)) override;
|
||||||
@ -38,6 +38,8 @@ public:
|
|||||||
IFACEMETHOD(RegisterCallback(_In_ ITerminationCallback* callback)) override;
|
IFACEMETHOD(RegisterCallback(_In_ ITerminationCallback* callback)) override;
|
||||||
IFACEMETHOD(GetDebugShellPipe(_Out_ LPWSTR* pipePath)) override;
|
IFACEMETHOD(GetDebugShellPipe(_Out_ LPWSTR* pipePath)) override;
|
||||||
IFACEMETHOD(MapPort(_In_ int Family, _In_ short WindowsPort, _In_ short LinuxPort, _In_ BOOL Remove)) override;
|
IFACEMETHOD(MapPort(_In_ int Family, _In_ short WindowsPort, _In_ short LinuxPort, _In_ BOOL Remove)) override;
|
||||||
|
IFACEMETHOD(Unmount(_In_ const char* Path)) override;
|
||||||
|
IFACEMETHOD(DetachDisk(_In_ ULONG Lun)) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void CALLBACK s_OnExit(_In_ HCS_EVENT* Event, _In_opt_ void* Context);
|
static void CALLBACK s_OnExit(_In_ HCS_EVENT* Event, _In_opt_ void* Context);
|
||||||
|
|||||||
@ -449,7 +449,7 @@ interface ITerminationCallback : IUnknown
|
|||||||
]
|
]
|
||||||
interface ILSWVirtualMachine : IUnknown
|
interface ILSWVirtualMachine : IUnknown
|
||||||
{
|
{
|
||||||
HRESULT AttachDisk([in] LPCWSTR Path, [in] BOOL ReadOnly, [out] LPSTR* Device);
|
HRESULT AttachDisk([in] LPCWSTR Path, [in] BOOL ReadOnly, [out] LPSTR* Device, [out] ULONG* Lun);
|
||||||
HRESULT Mount([in, unique] LPCSTR Source, [in] LPCSTR Target, [in] LPCSTR Type, [in] LPCSTR Options, [in] ULONG Flags);
|
HRESULT Mount([in, unique] LPCSTR Source, [in] LPCSTR Target, [in] LPCSTR Type, [in] LPCSTR Options, [in] ULONG Flags);
|
||||||
HRESULT CreateLinuxProcess([in] const LSW_CREATE_PROCESS_OPTIONS* Options, [in] ULONG FdCount, [in, unique, size_is(FdCount)] LSW_PROCESS_FD* Fds, [out, size_is(FdCount)] HVSOCKET_HANDLE* Handles, [out] LSW_CREATE_PROCESS_RESULT* Result);
|
HRESULT CreateLinuxProcess([in] const LSW_CREATE_PROCESS_OPTIONS* Options, [in] ULONG FdCount, [in, unique, size_is(FdCount)] LSW_PROCESS_FD* Fds, [out, size_is(FdCount)] HVSOCKET_HANDLE* Handles, [out] LSW_CREATE_PROCESS_RESULT* Result);
|
||||||
HRESULT WaitPid([in] LONG Pid, [in] ULONGLONG TimeoutMs, [out] ULONG* State, [out] int* Code);
|
HRESULT WaitPid([in] LONG Pid, [in] ULONGLONG TimeoutMs, [out] ULONG* State, [out] int* Code);
|
||||||
@ -458,6 +458,8 @@ interface ILSWVirtualMachine : IUnknown
|
|||||||
HRESULT RegisterCallback([in] ITerminationCallback* terminationCallback);
|
HRESULT RegisterCallback([in] ITerminationCallback* terminationCallback);
|
||||||
HRESULT GetDebugShellPipe([out] LPWSTR* pipePath);
|
HRESULT GetDebugShellPipe([out] LPWSTR* pipePath);
|
||||||
HRESULT MapPort([in] int Family, [in] short WindowsPort, [in] short LinuxPort, [in] BOOL Remove);
|
HRESULT MapPort([in] int Family, [in] short WindowsPort, [in] short LinuxPort, [in] BOOL Remove);
|
||||||
|
HRESULT Unmount([in] LPCSTR Path);
|
||||||
|
HRESULT DetachDisk([in] ULONG Lun);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef
|
typedef
|
||||||
|
|||||||
@ -122,6 +122,64 @@ class LSWTests
|
|||||||
return vm;
|
return vm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_METHOD(AttachDetach)
|
||||||
|
{
|
||||||
|
WSL2_TEST_ONLY();
|
||||||
|
|
||||||
|
VirtualMachineSettings settings{};
|
||||||
|
settings.CPU.CpuCount = 4;
|
||||||
|
settings.DisplayName = L"LSW";
|
||||||
|
settings.Memory.MemoryMb = 1024;
|
||||||
|
settings.Options.BootTimeoutMs = 30000;
|
||||||
|
auto vm = CreateVm(&settings);
|
||||||
|
|
||||||
|
#ifdef WSL_DEV_INSTALL_PATH
|
||||||
|
|
||||||
|
auto vhdPath = std::filesystem::path(WSL_DEV_INSTALL_PATH) / "system.vhd";
|
||||||
|
#else
|
||||||
|
|
||||||
|
auto msiPath = wsl::windows::common::wslutil::GetMsiPackagePath();
|
||||||
|
VERIFY_IS_TRUE(msiPath.has_value());
|
||||||
|
|
||||||
|
auto vhdPath = std::filesystem::path(msiPath.value()) / "system.vhd";
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
auto blockDeviceExists = [&](ULONG Lun) {
|
||||||
|
std::string device = std::format("/sys/bus/scsi/devices/0:0:0:{}", Lun);
|
||||||
|
std::vector<const char*> cmd{"/usr/bin/test", "-d", device.c_str()};
|
||||||
|
return RunCommand(vm.get(), cmd) == 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Attach the disk.
|
||||||
|
DiskAttachSettings attachSettings{vhdPath.c_str(), true};
|
||||||
|
AttachedDiskInformation attachedDisk{};
|
||||||
|
VERIFY_SUCCEEDED(WslAttachDisk(vm.get(), &attachSettings, &attachedDisk));
|
||||||
|
VERIFY_IS_TRUE(blockDeviceExists(attachedDisk.ScsiLun));
|
||||||
|
|
||||||
|
// Mount it to /mnt.
|
||||||
|
MountSettings mountSettings{attachedDisk.Device, "/mnt", "ext4", "ro"};
|
||||||
|
VERIFY_SUCCEEDED(WslMount(vm.get(), &mountSettings));
|
||||||
|
|
||||||
|
// Validate that the mountpoint is present.
|
||||||
|
std::vector<const char*> cmd{"/usr/bin/mountpoint", "/mnt"};
|
||||||
|
VERIFY_ARE_EQUAL(RunCommand(vm.get(), cmd), 0L);
|
||||||
|
|
||||||
|
// Unmount /mnt.
|
||||||
|
VERIFY_SUCCEEDED(WslUnmount(vm.get(), "/mnt"));
|
||||||
|
VERIFY_ARE_EQUAL(RunCommand(vm.get(), cmd), 32L);
|
||||||
|
|
||||||
|
// Verify that unmount fails now.
|
||||||
|
VERIFY_ARE_EQUAL(WslUnmount(vm.get(), "/mnt"), E_FAIL);
|
||||||
|
|
||||||
|
// Detach the disk
|
||||||
|
VERIFY_SUCCEEDED(WslDetachDisk(vm.get(), attachedDisk.ScsiLun));
|
||||||
|
VERIFY_IS_FALSE(blockDeviceExists(attachedDisk.ScsiLun));
|
||||||
|
|
||||||
|
// Verify that disk can't be detached twice
|
||||||
|
VERIFY_ARE_EQUAL(WslDetachDisk(vm.get(), attachedDisk.ScsiLun), HRESULT_FROM_WIN32(ERROR_NOT_FOUND));
|
||||||
|
}
|
||||||
|
|
||||||
TEST_METHOD(CustomDmesgOutput)
|
TEST_METHOD(CustomDmesgOutput)
|
||||||
{
|
{
|
||||||
WSL2_TEST_ONLY();
|
WSL2_TEST_ONLY();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user