mirror of https://github.com/microsoft/WSL
WSLA: Add virtiofs support for mounted Windows paths (#13880)
* WSLA: Add virtiofs support for mounted Windows paths * pr feedback and clarification on removing virtiofs shares --------- Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
This commit is contained in:
parent
c7e80fbd25
commit
9c01583fea
|
|
@ -345,6 +345,7 @@
|
|||
</RegistryKey>
|
||||
|
||||
<!-- wsldevicehost.dll -->
|
||||
<!-- TODO: WSL currently has two AppID registrations for wsldevicehost, is that needed? -->
|
||||
<RegistryKey Root="HKCR" Key="AppID\{C457EA11-5486-4174-B90D-089909EDB170}">
|
||||
<RegistryValue Name="DllSurrogate" Value="" Type="string" />
|
||||
<RegistryValue Name="AppIDFlags" Value="2048" Type="integer" />
|
||||
|
|
@ -354,9 +355,42 @@
|
|||
<RegistryValue Name="LaunchPermission" Value="01000480580000006800000000000000140000000200440003000000000014000B00000001010000000000050B000000000014000B00000001010000000000050A000000000014000B0000000101000000000005120000000102000000000005200000002002000001020000000000052000000020020000" Type="binary" />
|
||||
</RegistryKey>
|
||||
|
||||
<!-- WslDeviceHost_VirtioNet -->
|
||||
<!-- WslDeviceHost WSLA_VIRTIO_FS_ADMIN_CLASS_ID -->
|
||||
<RegistryKey Root="HKCR" Key="CLSID\{8F7C2A3B-D9E4-4C1F-A2B8-5E3D7C9F1A6E}">
|
||||
<RegistryValue Value="WslDeviceHost_VirtioFsAdmin" Type="string" />
|
||||
<RegistryValue Name="AppId" Value="{C457EA11-5486-4174-B90D-089909EDB170}" Type="string" />
|
||||
|
||||
<RegistryKey Key="InProcServer32">
|
||||
<RegistryValue Value="[INSTALLDIR]wsldevicehost.dll" Type="string" />
|
||||
<RegistryValue Name="ThreadingModel" Value="Both" Type="string" />
|
||||
</RegistryKey>
|
||||
</RegistryKey>
|
||||
|
||||
<!-- WslDeviceHost WSLA_VIRTIO_FS_CLASS_ID -->
|
||||
<RegistryKey Root="HKCR" Key="CLSID\{06ED032F-C528-41C1-B75D-905EEE823BBA}">
|
||||
<RegistryValue Value="WslDeviceHost_VirtioFs" Type="string" />
|
||||
<RegistryValue Name="AppId" Value="{C457EA11-5486-4174-B90D-089909EDB170}" Type="string" />
|
||||
|
||||
<RegistryKey Key="InProcServer32">
|
||||
<RegistryValue Value="[INSTALLDIR]wsldevicehost.dll" Type="string" />
|
||||
<RegistryValue Name="ThreadingModel" Value="Both" Type="string" />
|
||||
</RegistryKey>
|
||||
</RegistryKey>
|
||||
|
||||
<!-- WslDeviceHost WSLA_VIRTIO_NET_CLASS_ID -->
|
||||
<RegistryKey Root="HKCR" Key="CLSID\{7B3C9A42-8E1F-4D5A-9F2E-C4A7B8D3E6F1}">
|
||||
<RegistryValue Value="WslDeviceHost_Net" Type="string" />
|
||||
<RegistryValue Value="WslDeviceHost_VirtioNet" Type="string" />
|
||||
<RegistryValue Name="AppId" Value="{C457EA11-5486-4174-B90D-089909EDB170}" Type="string" />
|
||||
|
||||
<RegistryKey Key="InProcServer32">
|
||||
<RegistryValue Value="[INSTALLDIR]wsldevicehost.dll" Type="string" />
|
||||
<RegistryValue Name="ThreadingModel" Value="Both" Type="string" />
|
||||
</RegistryKey>
|
||||
</RegistryKey>
|
||||
|
||||
<!-- WslDeviceHost WSLA_VIRTIO_PMEM_CLASS_ID -->
|
||||
<RegistryKey Root="HKCR" Key="CLSID\{ABB755FC-1B86-4255-83E2-E5787ABCF6C2}">
|
||||
<RegistryValue Value="WslDeviceHost_VirtioPmem" Type="string" />
|
||||
<RegistryValue Name="AppId" Value="{C457EA11-5486-4174-B90D-089909EDB170}" Type="string" />
|
||||
|
||||
<RegistryKey Key="InProcServer32">
|
||||
|
|
|
|||
|
|
@ -26,4 +26,3 @@
|
|||
<clear />
|
||||
</disabledPackageSources>
|
||||
</configuration>
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
<package id="Microsoft.WSL.bsdtar" version="0.0.2-2" />
|
||||
<package id="Microsoft.WSL.Dependencies.amd64fre" version="10.0.27820.1000-250318-1700.rs-base2-hyp" targetFramework="native" />
|
||||
<package id="Microsoft.WSL.Dependencies.arm64fre" version="10.0.27820.1000-250318-1700.rs-base2-hyp" targetFramework="native" />
|
||||
<package id="Microsoft.WSL.DeviceHost" version="1.0.0-20251202.1" />
|
||||
<package id="Microsoft.WSL.DeviceHost" version="1.1.6-0" />
|
||||
<package id="Microsoft.WSL.Kernel" version="6.6.114.1-1" targetFramework="native" />
|
||||
<package id="Microsoft.WSL.LinuxSdk" version="1.20.0" targetFramework="native" />
|
||||
<package id="Microsoft.WSL.TestDistro" version="2.5.7-47" />
|
||||
|
|
|
|||
|
|
@ -1741,7 +1741,7 @@ Return Value:
|
|||
TimeoutSeconds.value(),
|
||||
[&]() {
|
||||
errno = wil::ResultFromCaughtException();
|
||||
return errno == ENOENT || errno == ENXIO || errno == EIO;
|
||||
return errno == ENOENT || errno == ENXIO || errno == EIO || ((strcmp(Type, VIRTIO_FS_TYPE) == 0) && (errno == EINVAL));
|
||||
});
|
||||
}
|
||||
else
|
||||
|
|
@ -1752,7 +1752,7 @@ Return Value:
|
|||
catch (...)
|
||||
{
|
||||
errno = wil::ResultFromCaughtException();
|
||||
LOG_ERROR("mount({}, {}, {}, 0x{}x, {}) failed {}", Source, Target, Type, MountFlags, Options, errno);
|
||||
LOG_ERROR("mount({}, {}, {}, {:#x}, {}) failed {}", Source, Target, Type, MountFlags, Options, errno);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1584,9 +1584,10 @@ struct WSLA_MOUNT
|
|||
enum MountType : uint8_t
|
||||
{
|
||||
None,
|
||||
Chroot = 1,
|
||||
OverlayFs = 2,
|
||||
KernelModules = 4
|
||||
ReadOnly = 1,
|
||||
Chroot = 2,
|
||||
OverlayFs = 4,
|
||||
KernelModules = 8
|
||||
};
|
||||
|
||||
char Buffer[];
|
||||
|
|
|
|||
|
|
@ -1552,6 +1552,8 @@ int WslaShell(_In_ std::wstring_view commandLine)
|
|||
parser.AddArgument(Utf8String(shell), L"--shell");
|
||||
parser.AddArgument(
|
||||
SetFlag<int, WslaFeatureFlagsDnsTunneling>(reinterpret_cast<int&>(sessionSettings.FeatureFlags)), L"--dns-tunneling");
|
||||
parser.AddArgument(
|
||||
SetFlag<int, WslaFeatureFlagsVirtioFs>(reinterpret_cast<int&>(sessionSettings.FeatureFlags)), L"--virtiofs");
|
||||
parser.AddArgument(Integer(sessionSettings.MemoryMb), L"--memory");
|
||||
parser.AddArgument(Integer(sessionSettings.CpuCount), L"--cpu");
|
||||
parser.AddArgument(Utf8String(rootVhdTypeOverride), L"--fstype");
|
||||
|
|
@ -1565,7 +1567,7 @@ int WslaShell(_In_ std::wstring_view commandLine)
|
|||
if (help)
|
||||
{
|
||||
const auto usage = std::format(
|
||||
LR"({} --wsla [--vhd </path/to/vhd>] [--shell </path/to/shell>] [--memory <memory-mb>] [--cpu <cpus>] [--dns-tunneling] [--networking-mode <mode>] [--fstype <fstype>] [--container-vhd </path/to/vhd>] [--help])",
|
||||
LR"({} --wsla [--vhd </path/to/vhd>] [--shell </path/to/shell>] [--memory <memory-mb>] [--cpu <cpus>] [--dns-tunneling] [--virtiofs] [--networking-mode <mode>] [--fstype <fstype>] [--container-vhd </path/to/vhd>] [--help])",
|
||||
WSL_BINARY_NAME);
|
||||
|
||||
wprintf(L"%ls\n", usage.c_str());
|
||||
|
|
|
|||
|
|
@ -34,7 +34,10 @@ constexpr auto SAVED_STATE_FILE_PREFIX = L"saved-state-";
|
|||
constexpr auto RECEIVE_TIMEOUT = 30 * 1000;
|
||||
|
||||
// WSLA-specific virtio device class IDs.
|
||||
DEFINE_GUID(WSLA_VIRTIO_FS_ADMIN_CLASS_ID, 0x8F7C2A3B, 0xD9E4, 0x4C1F, 0xA2, 0xB8, 0x5E, 0x3D, 0x7C, 0x9F, 0x1A, 0x6E); // {8F7C2A3B-D9E4-4C1F-A2B8-5E3D7C9F1A6E}
|
||||
DEFINE_GUID(WSLA_VIRTIO_FS_CLASS_ID, 0x06ED032F, 0xC528, 0x41C1, 0xB7, 0x5D, 0x90, 0x5E, 0xEE, 0x82, 0x3B, 0xBA); // {06ED032F-C528-41C1-B75D-905EEE823BBA}
|
||||
DEFINE_GUID(WSLA_VIRTIO_NET_CLASS_ID, 0x7B3C9A42, 0x8E1F, 0x4D5A, 0x9F, 0x2E, 0xC4, 0xA7, 0xB8, 0xD3, 0xE6, 0xF1); // {7B3C9A42-8E1F-4D5A-9F2E-C4A7B8D3E6F1}
|
||||
DEFINE_GUID(WSLA_VIRTIO_PMEM_CLASS_ID, 0xABB755FC, 0x1B86, 0x4255, 0x83, 0xE2, 0xE5, 0x78, 0x7A, 0xBC, 0xF6, 0xC2); // {ABB755FC-1B86-4255-83E2-E5787ABCF6C2}
|
||||
|
||||
WSLAVirtualMachine::WSLAVirtualMachine(WSLAVirtualMachine::Settings&& Settings, PSID UserSid) :
|
||||
m_settings(std::move(Settings)), m_userSid(UserSid)
|
||||
|
|
@ -306,8 +309,7 @@ void WSLAVirtualMachine::Start()
|
|||
WI_ASSERT(IsEqualGUID(m_vmId, runtimeId));
|
||||
|
||||
// Initialize DeviceHostProxy for virtio device support.
|
||||
// N.B. This is currently only needed for VirtioProxy networking mode but would also be needed for virtiofs.
|
||||
if (m_settings.NetworkingMode == WSLANetworkingModeVirtioProxy)
|
||||
if (FeatureEnabled(WslaFeatureFlagsVirtioFs) || m_settings.NetworkingMode == WSLANetworkingModeVirtioProxy)
|
||||
{
|
||||
m_guestDeviceManager = std::make_shared<GuestDeviceManager>(m_vmIdString, m_vmId);
|
||||
}
|
||||
|
|
@ -387,7 +389,7 @@ void WSLAVirtualMachine::ConfigureMounts()
|
|||
|
||||
if (FeatureEnabled(WslaFeatureFlagsGPU)) // TODO: re-think how GPU settings should work at the session level API.
|
||||
{
|
||||
MountGpuLibraries("/usr/lib/wsl/lib", "/usr/lib/wsl/drivers", WSLAMountFlagsNone);
|
||||
MountGpuLibraries("/usr/lib/wsl/lib", "/usr/lib/wsl/drivers");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -931,6 +933,7 @@ void WSLAVirtualMachine::Mount(LPCSTR Source, LPCSTR Target, LPCSTR Type, LPCSTR
|
|||
void WSLAVirtualMachine::Mount(shared::SocketChannel& Channel, LPCSTR Source, LPCSTR Target, LPCSTR Type, LPCSTR Options, ULONG Flags)
|
||||
{
|
||||
static_assert(WSLAMountFlagsNone == WSLA_MOUNT::None);
|
||||
static_assert(WSLAMountFlagsReadOnly == WSLA_MOUNT::ReadOnly);
|
||||
static_assert(WSLAMountFlagsChroot == WSLA_MOUNT::Chroot);
|
||||
static_assert(WSLAMountFlagsWriteableOverlayFs == WSLA_MOUNT::OverlayFs);
|
||||
|
||||
|
|
@ -1151,64 +1154,101 @@ CATCH_RETURN();
|
|||
|
||||
HRESULT WSLAVirtualMachine::MountWindowsFolder(_In_ LPCWSTR WindowsPath, _In_ LPCSTR LinuxPath, _In_ BOOL ReadOnly)
|
||||
{
|
||||
return MountWindowsFolderImpl(WindowsPath, LinuxPath, ReadOnly, WSLAMountFlagsNone);
|
||||
return MountWindowsFolderImpl(WindowsPath, LinuxPath, ReadOnly ? WSLAMountFlagsReadOnly : WSLAMountFlagsNone);
|
||||
}
|
||||
|
||||
HRESULT WSLAVirtualMachine::MountWindowsFolderImpl(_In_ LPCWSTR WindowsPath, _In_ LPCSTR LinuxPath, _In_ BOOL ReadOnly, _In_ WSLAMountFlags Flags)
|
||||
HRESULT WSLAVirtualMachine::MountWindowsFolderImpl(_In_ LPCWSTR WindowsPath, _In_ LPCSTR LinuxPath, _In_ WSLAMountFlags Flags)
|
||||
try
|
||||
{
|
||||
std::filesystem::path Path(WindowsPath);
|
||||
THROW_HR_IF_MSG(E_INVALIDARG, !Path.is_absolute(), "Path is not absolute: '%ls'", WindowsPath);
|
||||
std::filesystem::path path(WindowsPath);
|
||||
THROW_HR_IF_MSG(E_INVALIDARG, !path.is_absolute(), "Path is not absolute: '%ls'", WindowsPath);
|
||||
THROW_HR_IF_MSG(
|
||||
HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), !std::filesystem::is_directory(Path), "Path is not a directory: '%ls'", WindowsPath);
|
||||
HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND), !std::filesystem::is_directory(path), "Path is not a directory: '%ls'", WindowsPath);
|
||||
|
||||
GUID shareGuid{};
|
||||
THROW_IF_FAILED(CoCreateGuid(&shareGuid));
|
||||
|
||||
auto shareName = shared::string::GuidToString<wchar_t>(shareGuid, shared::string::None);
|
||||
|
||||
const auto userToken = wsl::windows::common::security::GetUserToken(TokenImpersonation);
|
||||
|
||||
{
|
||||
// Create the plan9 share on the host
|
||||
std::lock_guard lock(m_lock);
|
||||
|
||||
// Verify that this folder isn't already mounted.
|
||||
auto it = m_plan9Mounts.find(LinuxPath);
|
||||
THROW_HR_IF(HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS), it != m_plan9Mounts.end());
|
||||
auto it = m_mountedWindowsFolders.find(LinuxPath);
|
||||
THROW_HR_IF(HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS), it != m_mountedWindowsFolders.end());
|
||||
|
||||
hcs::AddPlan9Share(
|
||||
m_computeSystem.get(),
|
||||
shareName.c_str(),
|
||||
shareName.c_str(),
|
||||
WindowsPath,
|
||||
LX_INIT_UTILITY_VM_PLAN9_PORT,
|
||||
hcs::Plan9ShareFlags::AllowOptions | (ReadOnly ? hcs::Plan9ShareFlags::ReadOnly : hcs::Plan9ShareFlags::None),
|
||||
wsl::windows::common::security::GetUserToken(TokenImpersonation).get());
|
||||
if (!FeatureEnabled(WslaFeatureFlagsVirtioFs))
|
||||
{
|
||||
auto flags = hcs::Plan9ShareFlags::AllowOptions;
|
||||
WI_SetFlagIf(flags, hcs::Plan9ShareFlags::ReadOnly, WI_IsFlagSet(Flags, WSLAMountFlagsReadOnly));
|
||||
hcs::AddPlan9Share(
|
||||
m_computeSystem.get(),
|
||||
shareName.c_str(),
|
||||
shareName.c_str(),
|
||||
WindowsPath,
|
||||
LX_INIT_UTILITY_VM_PLAN9_PORT,
|
||||
flags,
|
||||
userToken.get());
|
||||
}
|
||||
else
|
||||
{
|
||||
const bool admin = wsl::windows::common::security::IsTokenElevated(userToken.get());
|
||||
m_guestDeviceManager->AddGuestDevice(
|
||||
VIRTIO_FS_DEVICE_ID,
|
||||
admin ? WSLA_VIRTIO_FS_ADMIN_CLASS_ID : WSLA_VIRTIO_FS_CLASS_ID,
|
||||
shareName.c_str(),
|
||||
L"",
|
||||
WindowsPath,
|
||||
VIRTIO_FS_FLAGS_TYPE_FILES,
|
||||
userToken.get());
|
||||
}
|
||||
|
||||
m_plan9Mounts.emplace(LinuxPath, shareName);
|
||||
m_mountedWindowsFolders.emplace(LinuxPath, shareName);
|
||||
}
|
||||
|
||||
auto deleteOnFailure = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [&]() {
|
||||
std::lock_guard lock(m_lock);
|
||||
LOG_HR_IF(E_UNEXPECTED, m_mountedWindowsFolders.erase(LinuxPath) != 1);
|
||||
|
||||
LOG_HR_IF(E_UNEXPECTED, m_plan9Mounts.erase(LinuxPath) != 1);
|
||||
if (!FeatureEnabled(WslaFeatureFlagsVirtioFs))
|
||||
{
|
||||
hcs::RemovePlan9Share(m_computeSystem.get(), shareName.c_str(), LX_INIT_UTILITY_VM_PLAN9_PORT);
|
||||
}
|
||||
});
|
||||
|
||||
// Create the guest mount
|
||||
auto [_, __, channel] = Fork(WSLA_FORK::Thread);
|
||||
|
||||
WSLA_CONNECT message;
|
||||
message.HostPort = LX_INIT_UTILITY_VM_PLAN9_PORT;
|
||||
|
||||
auto fd = channel.Transaction(message).Result;
|
||||
THROW_HR_IF_MSG(E_FAIL, fd < 0, "WSLA_CONNECT failed with %i", fd);
|
||||
|
||||
auto shareNameUtf8 = shared::string::WideToMultiByte(shareName);
|
||||
auto mountOptions =
|
||||
std::format("msize={},trans=fd,rfdno={},wfdno={},aname={},cache=mmap", LX_INIT_UTILITY_VM_PLAN9_BUFFER_SIZE, fd, fd, shareNameUtf8);
|
||||
if (!FeatureEnabled(WslaFeatureFlagsVirtioFs))
|
||||
{
|
||||
auto [_, __, channel] = Fork(WSLA_FORK::Thread);
|
||||
|
||||
Mount(channel, shareNameUtf8.c_str(), LinuxPath, "9p", mountOptions.c_str(), Flags);
|
||||
WSLA_CONNECT message;
|
||||
message.HostPort = LX_INIT_UTILITY_VM_PLAN9_PORT;
|
||||
|
||||
auto fd = channel.Transaction(message).Result;
|
||||
THROW_HR_IF_MSG(E_FAIL, fd < 0, "WSLA_CONNECT failed with %i", fd);
|
||||
|
||||
auto mountOptions = std::format(
|
||||
"{},msize={},trans=fd,rfdno={},wfdno={},aname={},cache=mmap",
|
||||
WI_IsFlagSet(Flags, WSLAMountFlagsReadOnly) ? "ro" : "rw",
|
||||
LX_INIT_UTILITY_VM_PLAN9_BUFFER_SIZE,
|
||||
fd,
|
||||
fd,
|
||||
shareNameUtf8);
|
||||
|
||||
Mount(channel, shareNameUtf8.c_str(), LinuxPath, "9p", mountOptions.c_str(), Flags);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string options = WI_IsFlagSet(Flags, WSLAMountFlagsReadOnly) ? "ro" : "rw";
|
||||
Mount(m_initChannel, shareNameUtf8.c_str(), LinuxPath, "virtiofs", options.c_str(), Flags);
|
||||
}
|
||||
|
||||
deleteOnFailure.release();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
CATCH_RETURN();
|
||||
|
|
@ -1219,23 +1259,27 @@ try
|
|||
std::lock_guard lock(m_lock);
|
||||
|
||||
// Verify that this folder is mounted.
|
||||
auto it = m_plan9Mounts.find(LinuxPath);
|
||||
THROW_HR_IF(HRESULT_FROM_WIN32(ERROR_NOT_FOUND), it == m_plan9Mounts.end());
|
||||
auto it = m_mountedWindowsFolders.find(LinuxPath);
|
||||
THROW_HR_IF(HRESULT_FROM_WIN32(ERROR_NOT_FOUND), it == m_mountedWindowsFolders.end());
|
||||
|
||||
// Unmount the folder from the guest. If the mount is not found, this most likely means that the guest unmounted it.
|
||||
auto result = Unmount(LinuxPath);
|
||||
THROW_HR_IF(result, FAILED(result) && result != HRESULT_FROM_WIN32(ERROR_NOT_FOUND));
|
||||
|
||||
// Remove the share from the host
|
||||
hcs::RemovePlan9Share(m_computeSystem.get(), it->second.c_str(), LX_INIT_UTILITY_VM_PLAN9_PORT);
|
||||
// Remove the share from the host.
|
||||
// N.B. VirtioFs shares are present until the VM is destroyed, since HCS currently lacks support for removing them dynamically.
|
||||
if (!FeatureEnabled(WslaFeatureFlagsVirtioFs))
|
||||
{
|
||||
hcs::RemovePlan9Share(m_computeSystem.get(), it->second.c_str(), LX_INIT_UTILITY_VM_PLAN9_PORT);
|
||||
}
|
||||
|
||||
m_plan9Mounts.erase(it);
|
||||
m_mountedWindowsFolders.erase(it);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
CATCH_RETURN();
|
||||
|
||||
void WSLAVirtualMachine::MountGpuLibraries(_In_ LPCSTR LibrariesMountPoint, _In_ LPCSTR DriversMountpoint, _In_ DWORD Flags)
|
||||
void WSLAVirtualMachine::MountGpuLibraries(_In_ LPCSTR LibrariesMountPoint, _In_ LPCSTR DriversMountpoint)
|
||||
{
|
||||
THROW_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_CONFIG_VALUE), !FeatureEnabled(WslaFeatureFlagsGPU));
|
||||
|
||||
|
|
@ -1245,7 +1289,7 @@ void WSLAVirtualMachine::MountGpuLibraries(_In_ LPCSTR LibrariesMountPoint, _In_
|
|||
|
||||
// Mount drivers.
|
||||
THROW_IF_FAILED(MountWindowsFolderImpl(
|
||||
std::format(L"{}\\System32\\DriverStore\\FileRepository", windowsPath).c_str(), DriversMountpoint, true, static_cast<WSLAMountFlags>(Flags)));
|
||||
std::format(L"{}\\System32\\DriverStore\\FileRepository", windowsPath).c_str(), DriversMountpoint, WSLAMountFlagsReadOnly));
|
||||
|
||||
// Mount the inbox libraries.
|
||||
auto inboxLibPath = std::format(L"{}\\System32\\lxss\\lib", windowsPath);
|
||||
|
|
@ -1253,7 +1297,7 @@ void WSLAVirtualMachine::MountGpuLibraries(_In_ LPCSTR LibrariesMountPoint, _In_
|
|||
if (std::filesystem::is_directory(inboxLibPath))
|
||||
{
|
||||
inboxLibMountPoint = std::format("{}/inbox", LibrariesMountPoint);
|
||||
THROW_IF_FAILED(MountWindowsFolder(inboxLibPath.c_str(), inboxLibMountPoint->c_str(), true));
|
||||
THROW_IF_FAILED(MountWindowsFolderImpl(inboxLibPath.c_str(), inboxLibMountPoint->c_str(), WSLAMountFlagsReadOnly));
|
||||
}
|
||||
|
||||
// Mount the packaged libraries.
|
||||
|
|
@ -1269,7 +1313,7 @@ void WSLAVirtualMachine::MountGpuLibraries(_In_ LPCSTR LibrariesMountPoint, _In_
|
|||
#endif
|
||||
|
||||
auto packagedLibMountPoint = std::format("{}/packaged", LibrariesMountPoint);
|
||||
THROW_IF_FAILED(MountWindowsFolder(packagedLibPath.c_str(), packagedLibMountPoint.c_str(), true));
|
||||
THROW_IF_FAILED(MountWindowsFolderImpl(packagedLibPath.c_str(), packagedLibMountPoint.c_str(), WSLAMountFlagsReadOnly));
|
||||
|
||||
// Mount an overlay containing both inbox and packaged libraries (the packaged mount takes precedence).
|
||||
std::string options = "lowerdir=" + packagedLibMountPoint;
|
||||
|
|
@ -1278,7 +1322,7 @@ void WSLAVirtualMachine::MountGpuLibraries(_In_ LPCSTR LibrariesMountPoint, _In_
|
|||
options += ":" + inboxLibMountPoint.value();
|
||||
}
|
||||
|
||||
Mount(m_initChannel, "none", LibrariesMountPoint, "overlay", options.c_str(), Flags);
|
||||
Mount(m_initChannel, "none", LibrariesMountPoint, "overlay", options.c_str(), 0);
|
||||
}
|
||||
|
||||
std::filesystem::path WSLAVirtualMachine::GetCrashDumpFolder()
|
||||
|
|
|
|||
|
|
@ -27,8 +27,9 @@ namespace wsl::windows::service::wsla {
|
|||
enum WSLAMountFlags
|
||||
{
|
||||
WSLAMountFlagsNone = 0,
|
||||
WSLAMountFlagsChroot = 1,
|
||||
WSLAMountFlagsWriteableOverlayFs = 2,
|
||||
WSLAMountFlagsReadOnly = 1,
|
||||
WSLAMountFlagsChroot = 2,
|
||||
WSLAMountFlagsWriteableOverlayFs = 4,
|
||||
};
|
||||
|
||||
class WSLAUserSessionImpl;
|
||||
|
|
@ -74,7 +75,6 @@ public:
|
|||
IFACEMETHOD(Unmount(_In_ const char* Path)) override;
|
||||
IFACEMETHOD(MountWindowsFolder(_In_ LPCWSTR WindowsPath, _In_ LPCSTR LinuxPath, _In_ BOOL ReadOnly)) override;
|
||||
IFACEMETHOD(UnmountWindowsFolder(_In_ LPCSTR LinuxPath)) override;
|
||||
void MountGpuLibraries(_In_ LPCSTR LibrariesMountPoint, _In_ LPCSTR DriversMountpoint, _In_ DWORD Flags);
|
||||
|
||||
void OnProcessReleased(int Pid);
|
||||
void RegisterCallback(_In_ ITerminationCallback* callback);
|
||||
|
|
@ -88,6 +88,7 @@ public:
|
|||
|
||||
private:
|
||||
static void Mount(wsl::shared::SocketChannel& Channel, LPCSTR Source, _In_ LPCSTR Target, _In_ LPCSTR Type, _In_ LPCSTR Options, _In_ ULONG Flags);
|
||||
void MountGpuLibraries(_In_ LPCSTR LibrariesMountPoint, _In_ LPCSTR DriversMountpoint);
|
||||
static void CALLBACK s_OnExit(_In_ HCS_EVENT* Event, _In_opt_ void* Context);
|
||||
static bool ParseTtyInformation(
|
||||
const WSLA_PROCESS_FD* Fds, ULONG FdCount, const WSLA_PROCESS_FD** TtyInput, const WSLA_PROCESS_FD** TtyOutput, const WSLA_PROCESS_FD** TtyControl);
|
||||
|
|
@ -116,7 +117,7 @@ private:
|
|||
Microsoft::WRL::ComPtr<WSLAProcess> CreateLinuxProcessImpl(
|
||||
_In_ const WSLA_PROCESS_OPTIONS& Options, int* Errno = nullptr, const TPrepareCommandLine& PrepareCommandLine = [](const auto&) {});
|
||||
|
||||
HRESULT MountWindowsFolderImpl(_In_ LPCWSTR WindowsPath, _In_ LPCSTR LinuxPath, _In_ BOOL ReadOnly, _In_ WSLAMountFlags Flags);
|
||||
HRESULT MountWindowsFolderImpl(_In_ LPCWSTR WindowsPath, _In_ LPCSTR LinuxPath, _In_ WSLAMountFlags Flags = WSLAMountFlagsNone);
|
||||
|
||||
void WatchForExitedProcesses(wsl::shared::SocketChannel& Channel);
|
||||
|
||||
|
|
@ -162,7 +163,7 @@ private:
|
|||
wil::unique_handle m_portRelayChannelWrite;
|
||||
|
||||
std::map<ULONG, AttachedDisk> m_attachedDisks;
|
||||
std::map<std::string, std::wstring> m_plan9Mounts;
|
||||
std::map<std::string, std::wstring> m_mountedWindowsFolders;
|
||||
std::recursive_mutex m_lock;
|
||||
std::mutex m_portRelaylock;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -227,10 +227,11 @@ typedef enum _WSLANetworkingMode
|
|||
|
||||
typedef enum _WSLAFeatureFlags
|
||||
{
|
||||
WslaFeatureFlagsNone = 0,
|
||||
WslaFeatureFlagsDnsTunneling = 1,
|
||||
WslaFeatureFlagsEarlyBootDmesg = 2,
|
||||
WslaFeatureFlagsGPU = 4,
|
||||
WslaFeatureFlagsNone = 0,
|
||||
WslaFeatureFlagsDnsTunneling = 1,
|
||||
WslaFeatureFlagsEarlyBootDmesg = 2,
|
||||
WslaFeatureFlagsGPU = 4,
|
||||
WslaFeatureFlagsVirtioFs = 8,
|
||||
} WSLAFeatureFlags;
|
||||
|
||||
struct WSLA_SESSION_SETTINGS {
|
||||
|
|
@ -246,7 +247,7 @@ struct WSLA_SESSION_SETTINGS {
|
|||
ULONG DmesgOutput;
|
||||
|
||||
// Below options are used for debugging purposes only.
|
||||
[unique] LPCWSTR RootVhdOverride;
|
||||
[unique] LPCWSTR RootVhdOverride;
|
||||
[unique] LPCSTR RootVhdTypeOverride;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -711,16 +711,29 @@ class WSLATests
|
|||
StopWslaService();
|
||||
}
|
||||
|
||||
TEST_METHOD(WindowsMounts)
|
||||
void ValidateWindowsMounts(bool enableVirtioFs)
|
||||
{
|
||||
WSL2_TEST_ONLY();
|
||||
auto settings = GetDefaultSessionSettings();
|
||||
WI_SetFlagIf(settings.FeatureFlags, WslaFeatureFlagsVirtioFs, enableVirtioFs);
|
||||
|
||||
auto session = CreateSession();
|
||||
auto session = CreateSession(settings);
|
||||
|
||||
wil::com_ptr<IWSLAVirtualMachine> vm;
|
||||
VERIFY_SUCCEEDED(session->GetVirtualMachine(&vm));
|
||||
wsl::windows::common::security::ConfigureForCOMImpersonation(vm.get());
|
||||
|
||||
auto expectedMountOptions = [&](bool readOnly) -> std::string {
|
||||
if (enableVirtioFs)
|
||||
{
|
||||
return std::format("/win-path*virtiofs*{},relatime*", readOnly ? "ro" : "rw");
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::format(
|
||||
"/win-path*9p*{},relatime,aname=*,cache=5,access=client,msize=65536,trans=fd,rfd=*,wfd=*", readOnly ? "ro" : "rw");
|
||||
}
|
||||
};
|
||||
|
||||
auto expectMount = [&](const std::string& target, const std::optional<std::string>& options) {
|
||||
auto cmd = std::format("set -o pipefail ; findmnt '{}' | tail -n 1", target);
|
||||
|
||||
|
|
@ -749,7 +762,7 @@ class WSLATests
|
|||
// Validate writeable mount.
|
||||
{
|
||||
VERIFY_SUCCEEDED(vm->MountWindowsFolder(testFolder.c_str(), "/win-path", false));
|
||||
expectMount("/win-path", "/win-path*9p*rw,relatime,aname=*,cache=5,access=client,msize=65536,trans=fd,rfd=*,wfd=*");
|
||||
expectMount("/win-path", expectedMountOptions(false));
|
||||
|
||||
// Validate that mount can't be stacked on each other
|
||||
VERIFY_ARE_EQUAL(vm->MountWindowsFolder(testFolder.c_str(), "/win-path", false), HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS));
|
||||
|
|
@ -765,7 +778,7 @@ class WSLATests
|
|||
// Validate read-only mount.
|
||||
{
|
||||
VERIFY_SUCCEEDED(vm->MountWindowsFolder(testFolder.c_str(), "/win-path", true));
|
||||
expectMount("/win-path", "/win-path*9p*rw,relatime,aname=*,cache=5,access=client,msize=65536,trans=fd,rfd=*,wfd=*");
|
||||
expectMount("/win-path", expectedMountOptions(true));
|
||||
|
||||
// Validate that folder is not writeable from linux
|
||||
ExpectCommandResult(session.get(), {"/bin/sh", "-c", "echo -n content > /win-path/file.txt"}, 1);
|
||||
|
|
@ -783,13 +796,25 @@ class WSLATests
|
|||
|
||||
// Validate that folders that are manually unmounted from the guest are handled properly
|
||||
VERIFY_SUCCEEDED(vm->MountWindowsFolder(testFolder.c_str(), "/win-path", true));
|
||||
expectMount("/win-path", "/win-path*9p*rw,relatime,aname=*,cache=5,access=client,msize=65536,trans=fd,rfd=*,wfd=*");
|
||||
expectMount("/win-path", expectedMountOptions(true));
|
||||
|
||||
ExpectCommandResult(session.get(), {"/usr/bin/umount", "/win-path"}, 0);
|
||||
VERIFY_SUCCEEDED(vm->UnmountWindowsFolder("/win-path"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_METHOD(WindowsMounts)
|
||||
{
|
||||
WSL2_TEST_ONLY();
|
||||
ValidateWindowsMounts(false);
|
||||
}
|
||||
|
||||
TEST_METHOD(WindowsMountsVirtioFs)
|
||||
{
|
||||
WSL2_TEST_ONLY();
|
||||
ValidateWindowsMounts(true);
|
||||
}
|
||||
|
||||
// This test case validates that no file descriptors are leaked to user processes.
|
||||
TEST_METHOD(Fd)
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue