From 5f4672011fb2beaaa6888f2c296a673143429716 Mon Sep 17 00:00:00 2001 From: artiga033 Date: Thu, 20 Nov 2025 23:36:08 +0800 Subject: [PATCH 01/21] PoC --- localization/strings/en-US/Resources.resw | 7 ++++++ localization/strings/zh-CN/Resources.resw | 7 ++++++ src/linux/init/main.cpp | 23 ++++++++++++++----- src/windows/common/WslClient.cpp | 10 ++++++-- src/windows/common/WslInstall.cpp | 18 +++++++++++---- src/windows/common/WslInstall.h | 8 +++++-- src/windows/common/svccomm.cpp | 6 +++++ src/windows/common/svccomm.hpp | 2 ++ src/windows/inc/wsl.h | 2 ++ .../service/exe/DistributionRegistration.cpp | 23 ++++++++++++++++++- .../service/exe/DistributionRegistration.h | 4 ++++ src/windows/service/exe/LxssCreateProcess.h | 2 ++ src/windows/service/exe/LxssUserSession.cpp | 21 ++++++++++++++--- src/windows/service/exe/LxssUserSession.h | 6 +++++ src/windows/service/exe/WslCoreVm.cpp | 5 ++-- src/windows/service/inc/wslservice.idl | 4 ++++ 16 files changed, 127 insertions(+), 21 deletions(-) diff --git a/localization/strings/en-US/Resources.resw b/localization/strings/en-US/Resources.resw index 55a700b83..ace4df40c 100644 --- a/localization/strings/en-US/Resources.resw +++ b/localization/strings/en-US/Resources.resw @@ -436,6 +436,13 @@ Arguments for managing Windows Subsystem for Linux: --from-file <Path> Install a distribution from a local file. + --fs-type + Specify the filesystem type to use for the distribution root. + Defaults to ext4. + + --fs-mount-options + Specify additional mount options for the filesystem. + --legacy Use the legacy distribution manifest. diff --git a/localization/strings/zh-CN/Resources.resw b/localization/strings/zh-CN/Resources.resw index 30f2e9a36..eb50631ff 100644 --- a/localization/strings/zh-CN/Resources.resw +++ b/localization/strings/zh-CN/Resources.resw @@ -442,6 +442,13 @@ --from-file <Path> 从本地文件安装发行版。 + --fs-type + 指定用于分发版根目录的文件系统类型。 + 默认为 ext4。 + + --fs-mount-options + 指定根目录文件系统的其他装载选项。 + --legacy 使用旧发行版清单。 diff --git a/src/linux/init/main.cpp b/src/linux/init/main.cpp index e8e831502..843b1942a 100644 --- a/src/linux/init/main.cpp +++ b/src/linux/init/main.cpp @@ -136,7 +136,7 @@ int EnableInterface(int Socket, const char* Name); int ExportToSocket(const char* Source, int Socket, int ErrorSocket, unsigned int flags); -int FormatDevice(unsigned int Lun); +int FormatDevice(unsigned int Lun, const char* FsType); std::string GetLunDeviceName(unsigned int Lun); @@ -901,7 +901,7 @@ Return Value: return Result; } -int FormatDevice(unsigned int Lun) +int FormatDevice(unsigned int Lun, const char* FsType) /*++ @@ -914,6 +914,7 @@ Routine Description: Arguments: Lun - Supplies the LUN number of the SCSI device. + FsType - The filesystem type to format the device with. Return Value: @@ -927,7 +928,16 @@ try WaitForBlockDevice(DevicePath.c_str()); - std::string CommandLine = std::format("/usr/sbin/mkfs.ext4 -G 4096 '{}'", DevicePath); + std::string CommandLine; + std::string FsType_s = std::string(FsType); + if (FsType_s == "ext4") + { + CommandLine = std::format("/usr/sbin/mkfs.ext4 -G 4096 '{}'", DevicePath); + } + else if (FsType_s == "btrfs") + { + CommandLine = std::format("/usr/sbin/mkfs.btrfs '{}'", DevicePath); + } if (UtilExecCommandLine(CommandLine.c_str(), nullptr) < 0) { return -1; @@ -2738,13 +2748,14 @@ void ProcessImportExportMessage(gsl::span Buffer, wsl::shared::Socket ListenSocket = UtilListenVsockAnyPort(&ListenAddress, 2, true); THROW_LAST_ERROR_IF(!ListenSocket); + auto* FsType = wsl::shared::string::FromSpan(Buffer, Message->FsTypeOffset); + auto* MountOptions = wsl::shared::string::FromSpan(Buffer, Message->MountOptionsOffset); + if (Message->Header.MessageType == LxMiniInitMessageImport) { - THROW_LAST_ERROR_IF(FormatDevice(Message->DeviceId) < 0); + THROW_LAST_ERROR_IF(FormatDevice(Message->DeviceId, FsType) < 0); } - auto* FsType = wsl::shared::string::FromSpan(Buffer, Message->FsTypeOffset); - auto* MountOptions = wsl::shared::string::FromSpan(Buffer, Message->MountOptionsOffset); THROW_LAST_ERROR_IF(MountDevice(Message->MountDeviceType, Message->DeviceId, DISTRO_PATH, FsType, Message->Flags, MountOptions) < 0); Result = 0; diff --git a/src/windows/common/WslClient.cpp b/src/windows/common/WslClient.cpp index 72daeecae..34ca5756b 100644 --- a/src/windows/common/WslClient.cpp +++ b/src/windows/common/WslClient.cpp @@ -458,6 +458,8 @@ int Install(_In_ std::wstring_view commandLine) bool noDistribution = false; bool legacy = false; bool webDownload = IsWindowsServer(); + std::optional fsType; + std::optional fsMountOptions; ArgumentParser parser(std::wstring{commandLine}, WSL_BINARY_NAME); parser.AddPositionalArgument(distroArgument, 0); @@ -475,6 +477,8 @@ int Install(_In_ std::wstring_view commandLine) parser.AddArgument(g_promptBeforeExit, WSL_INSTALL_ARG_PROMPT_BEFORE_EXIT_OPTION); parser.AddArgument(SizeString(vhdSize), WSL_INSTALL_ARG_VHD_SIZE); parser.AddArgument(fixedVhd, WSL_INSTALL_ARG_FIXED_VHD); + parser.AddArgument(fsType, WSL_INSTALL_ARG_FS_TYPE); + parser.AddArgument(fsMountOptions, WSL_INSTALL_ARG_FS_MOUNT_OPTIONS); parser.Parse(); @@ -531,7 +535,9 @@ int Install(_In_ std::wstring_view commandLine) file, location.has_value() ? location->c_str() : nullptr, fixedVhd ? LXSS_IMPORT_DISTRO_FLAGS_FIXED_VHD : 0, - vhdSize); + vhdSize, + fsType.has_value() ? fsType->c_str() : nullptr, + fsMountOptions.has_value() ? fsMountOptions->c_str() : nullptr); wsl::windows::common::wslutil::PrintMessage(Localization::MessageDistributionInstalled(installedName.get()), stdout); @@ -557,7 +563,7 @@ int Install(_In_ std::wstring_view commandLine) if (!noDistribution && (legacy || !rebootRequired)) { auto result = WslInstall::InstallDistribution( - installResult, distroArgument, version, !noLaunchAfterInstall, webDownload, legacy, fixedVhd, name, location, vhdSize); + installResult, distroArgument, version, !noLaunchAfterInstall, webDownload, legacy, fixedVhd, name, location, vhdSize, fsType, fsMountOptions); std::optional flavor; if (installResult.Distribution.has_value()) diff --git a/src/windows/common/WslInstall.cpp b/src/windows/common/WslInstall.cpp index 1aab74850..648f13dee 100644 --- a/src/windows/common/WslInstall.cpp +++ b/src/windows/common/WslInstall.cpp @@ -101,7 +101,9 @@ HRESULT WslInstall::InstallDistribution( _In_ bool fixedVhd, _In_ const std::optional& localName, _In_ const std::optional& location, - _In_ const std::optional& vhdSize) + _In_ const std::optional& vhdSize, + _In_ const std::optional& fsType, + _In_ const std::optional& fsMountOptions) try { wsl::windows::common::ExecutionContext context(wsl::windows::common::InstallDistro); @@ -143,7 +145,7 @@ try if (const auto* distro = std::get_if(&*installResult.Distribution)) { std::tie(installResult.Name, installResult.Id) = - InstallModernDistribution(*distro, version, localName, location, vhdSize, fixedVhd); + InstallModernDistribution(*distro, version, localName, location, vhdSize, fixedVhd, fsType, fsMountOptions); installResult.InstalledViaGitHub = true; } @@ -153,7 +155,9 @@ try {localName.has_value(), WSL_INSTALL_ARG_NAME_LONG}, {location.has_value(), WSL_INSTALL_ARG_LOCATION_LONG}, {vhdSize.has_value(), WSL_INSTALL_ARG_VHD_SIZE}, - {fixedVhd, WSL_INSTALL_ARG_FIXED_VHD}}; + {fixedVhd, WSL_INSTALL_ARG_FIXED_VHD}, + {fsType.has_value(), WSL_INSTALL_ARG_FS_TYPE}, + {fsMountOptions.has_value(), WSL_INSTALL_ARG_FS_MOUNT_OPTIONS}}; for (const auto& [condition, argument] : unsupportedArguments) { @@ -272,7 +276,9 @@ std::pair WslInstall::InstallModernDistribution( const std::optional& name, const std::optional& location, const std::optional& vhdSize, - const bool fixedVhd) + const bool fixedVhd, + const std::optional& fsType, + const std::optional& fsMountOptions) { wsl::windows::common::SvcComm service; @@ -322,7 +328,9 @@ std::pair WslInstall::InstallModernDistribution( file.get(), location.has_value() ? location->c_str() : nullptr, fixedVhd ? LXSS_IMPORT_DISTRO_FLAGS_FIXED_VHD : 0, - vhdSize); + vhdSize, + fsType.has_value() ? fsType->c_str() : nullptr, + fsMountOptions.has_value() ? fsMountOptions->c_str() : nullptr); return {installedName.get(), id}; } \ No newline at end of file diff --git a/src/windows/common/WslInstall.h b/src/windows/common/WslInstall.h index beee2fa24..89082d697 100644 --- a/src/windows/common/WslInstall.h +++ b/src/windows/common/WslInstall.h @@ -38,7 +38,9 @@ class WslInstall _In_ bool fixedVhd, _In_ const std::optional& localName, _In_ const std::optional& location, - _In_ const std::optional& vhdSize); + _In_ const std::optional& vhdSize, + _In_ const std::optional& fsType, + _In_ const std::optional& fsMountOptions); static std::pair> CheckForMissingOptionalComponents(_In_ bool requireWslOptionalComponent); @@ -50,5 +52,7 @@ class WslInstall const std::optional& name, const std::optional& location, const std::optional& vhdSize, - const bool fixedVhd); + const bool fixedVhd, + const std::optional& fsType, + const std::optional& fsMountOptions); }; diff --git a/src/windows/common/svccomm.cpp b/src/windows/common/svccomm.cpp index cc066c2b8..8db1c8bb8 100644 --- a/src/windows/common/svccomm.cpp +++ b/src/windows/common/svccomm.cpp @@ -914,6 +914,8 @@ std::pair wsl::windows::common::SvcComm::Reg _In_ LPCWSTR TargetDirectory, _In_ ULONG Flags, _In_ std::optional VhdSize, + _In_ LPCWSTR FsType, + _In_ LPCWSTR MountOptions, _In_opt_ LPCWSTR PackageFamilyName) const { ClientExecutionContext context; @@ -939,6 +941,8 @@ std::pair wsl::windows::common::SvcComm::Reg TargetDirectory, Flags, VhdSize.value_or(0), + FsType, + MountOptions, PackageFamilyName, &installedName, context.OutError(), @@ -954,6 +958,8 @@ std::pair wsl::windows::common::SvcComm::Reg TargetDirectory, Flags, VhdSize.value_or(0), + FsType, + MountOptions, PackageFamilyName, &installedName, context.OutError(), diff --git a/src/windows/common/svccomm.hpp b/src/windows/common/svccomm.hpp index 3a6423a58..e86dcea1f 100644 --- a/src/windows/common/svccomm.hpp +++ b/src/windows/common/svccomm.hpp @@ -86,6 +86,8 @@ class SvcComm _In_ LPCWSTR TargetDirectory, _In_ ULONG Flags, _In_ std::optional VhdSize = std::nullopt, + _In_ LPCWSTR FsType = L"ext4", + _In_ LPCWSTR FsMountOptions = L"discard,errors=remount-ro,data=ordered", _In_opt_ LPCWSTR PackageFamilyName = nullptr) const; HRESULT diff --git a/src/windows/inc/wsl.h b/src/windows/inc/wsl.h index ce4b9e430..b5516bb69 100644 --- a/src/windows/inc/wsl.h +++ b/src/windows/inc/wsl.h @@ -40,6 +40,8 @@ Module Name: #define WSL_INSTALL_ARG_FIXED_VHD L"--fixed-vhd" #define WSL_INSTALL_ARG_FROM_FILE_OPTION L'f' #define WSL_INSTALL_ARG_FROM_FILE_LONG L"--from-file" +#define WSL_INSTALL_ARG_FS_MOUNT_OPTIONS L"--fs-mount-options" +#define WSL_INSTALL_ARG_FS_TYPE L"--fs-type" #define WSL_INSTALL_ARG_LEGACY_LONG L"--legacy" #define WSL_INSTALL_ARG_LOCATION_OPTION L'l' #define WSL_INSTALL_ARG_LOCATION_LONG L"--location" diff --git a/src/windows/service/exe/DistributionRegistration.cpp b/src/windows/service/exe/DistributionRegistration.cpp index bfda98c2f..e42a5ec0b 100644 --- a/src/windows/service/exe/DistributionRegistration.cpp +++ b/src/windows/service/exe/DistributionRegistration.cpp @@ -57,7 +57,18 @@ DistributionRegistration DistributionRegistration::Open(HKEY LxssKey, const GUID } DistributionRegistration DistributionRegistration::Create( - HKEY LxssKey, const std::optional& Id, LPCWSTR Name, ULONG Version, LPCWSTR BasePath, ULONG Flags, ULONG DefaultUID, LPCWSTR PackageFamilyName, LPCWSTR VhdFileName, bool EnableOobe) + HKEY LxssKey, + const std::optional& Id, + LPCWSTR Name, + ULONG Version, + LPCWSTR BasePath, + ULONG Flags, + ULONG DefaultUID, + LPCWSTR PackageFamilyName, + LPCWSTR VhdFileName, + LPCWSTR FsType, + LPCWSTR FsMountOptions, + bool EnableOobe) { std::wstring distroGuidString; GUID distroId{}; @@ -112,6 +123,16 @@ DistributionRegistration DistributionRegistration::Create( distribution.Write(Property::VhdFileName, VhdFileName); } + if (ARGUMENT_PRESENT(FsType)) + { + distribution.Write(Property::FsType, FsType); + } + + if (ARGUMENT_PRESENT(FsMountOptions)) + { + distribution.Write(Property::FsMountOptions, FsMountOptions); + } + // Dismiss the scope exit member so the key is persisted. cleanup.release(); return distribution; diff --git a/src/windows/service/exe/DistributionRegistration.h b/src/windows/service/exe/DistributionRegistration.h index 61fc161d4..adeb337d4 100644 --- a/src/windows/service/exe/DistributionRegistration.h +++ b/src/windows/service/exe/DistributionRegistration.h @@ -55,6 +55,8 @@ class DistributionRegistration ULONG DefaultUID, LPCWSTR PackageFamilyName, LPCWSTR VhdFileName, + LPCWSTR FsType, + LPCWSTR FsMountOptions, bool EnableOobe); static DistributionRegistration Open(HKEY LxssKey, const GUID& Id); @@ -91,6 +93,8 @@ namespace Property { inline DistributionPropertyWithDefault PackageFamilyName{L"PackageFamilyName", L""}; inline DistributionPropertyWithDefault KernelCommandLine{L"KernelCommandLine", L""}; inline DistributionPropertyWithDefault VhdFileName{L"VhdFileName", LXSS_VM_MODE_VHD_NAME}; + inline DistributionPropertyWithDefault FsType{L"FsType", L"ext4"}; + inline DistributionPropertyWithDefault FsMountOptions{L"FsMountOptions", L"discard,errors=remount-ro,data=ordered"}; inline ExpectedProperty Name{L"DistributionName"}; inline ExpectedProperty BasePath{L"BasePath"}; inline DistributionProperty Flavor{L"Flavor"}; diff --git a/src/windows/service/exe/LxssCreateProcess.h b/src/windows/service/exe/LxssCreateProcess.h index 8e1c704a4..8fd4bc602 100644 --- a/src/windows/service/exe/LxssCreateProcess.h +++ b/src/windows/service/exe/LxssCreateProcess.h @@ -110,6 +110,8 @@ typedef struct _LXSS_DISTRO_CONFIGURATION std::filesystem::path BasePath; std::wstring PackageFamilyName; std::filesystem::path VhdFilePath; + std::wstring FsType; + std::wstring FsMountOptions; ULONG Flags; std::wstring Flavor; std::wstring OsVersion; diff --git a/src/windows/service/exe/LxssUserSession.cpp b/src/windows/service/exe/LxssUserSession.cpp index 2ad6469c9..cdb2db86a 100644 --- a/src/windows/service/exe/LxssUserSession.cpp +++ b/src/windows/service/exe/LxssUserSession.cpp @@ -383,6 +383,8 @@ HRESULT STDMETHODCALLTYPE LxssUserSession::RegisterDistribution( _In_ LPCWSTR TargetDirectory, _In_ ULONG Flags, _In_ ULONG64 VhdSize, + _In_ LPCWSTR FsType, + _In_ LPCWSTR FsMountOptions, _In_opt_ LPCWSTR PackageFamilyName, _Out_ LPWSTR* InstalledDistributionName, _Out_ LXSS_ERROR_INFO* Error, @@ -395,7 +397,7 @@ try RETURN_HR_IF(RPC_E_DISCONNECTED, !session); return session->RegisterDistribution( - DistributionName, Version, FileHandle, ErrorHandle, TargetDirectory, Flags, VhdSize, PackageFamilyName, InstalledDistributionName, pDistroGuid); + DistributionName, Version, FileHandle, ErrorHandle, TargetDirectory, Flags, VhdSize, FsType, FsMountOptions, PackageFamilyName, InstalledDistributionName, pDistroGuid); } CATCH_RETURN() @@ -415,6 +417,8 @@ try TargetDirectory, 0, 0, + nullptr, + nullptr, packageFamilyName.empty() ? nullptr : packageFamilyName.c_str(), nullptr, nullptr, @@ -430,6 +434,8 @@ HRESULT STDMETHODCALLTYPE LxssUserSession::RegisterDistributionPipe( _In_ LPCWSTR TargetDirectory, _In_ ULONG Flags, _In_ ULONG64 VhdSize, + _In_ LPCWSTR FsType, + _In_ LPCWSTR FsMountOptions, _In_opt_ LPCWSTR PackageFamilyName, _Out_ LPWSTR* InstalledDistributionName, _Out_ LXSS_ERROR_INFO* Error, @@ -442,7 +448,7 @@ try RETURN_HR_IF(RPC_E_DISCONNECTED, !session); return session->RegisterDistribution( - DistributionName, Version, PipeHandle, ErrorHandle, TargetDirectory, Flags, VhdSize, PackageFamilyName, InstalledDistributionName, pDistroGuid); + DistributionName, Version, PipeHandle, ErrorHandle, TargetDirectory, Flags, VhdSize, FsType, FsMountOptions, PackageFamilyName, InstalledDistributionName, pDistroGuid); } CATCH_RETURN() @@ -1297,6 +1303,8 @@ LxssUserSessionImpl::ImportDistributionInplace(_In_ LPCWSTR DistributionName, _I LX_UID_ROOT, nullptr, path.filename().c_str(), + nullptr, + nullptr, false); auto configuration = s_GetDistributionConfiguration(registration); @@ -1350,6 +1358,8 @@ HRESULT LxssUserSessionImpl::RegisterDistribution( _In_ LPCWSTR TargetDirectory, _In_ ULONG Flags, _In_ ULONG64 VhdSize, + _In_ LPCWSTR FsType, + _In_ LPCWSTR FsMountOptions, _In_opt_ LPCWSTR PackageFamilyName, _Out_opt_ LPWSTR* InstalledDistributionName, _Out_ GUID* pDistroGuid) @@ -1488,6 +1498,8 @@ HRESULT LxssUserSessionImpl::RegisterDistribution( LX_UID_ROOT, PackageFamilyName, vhdName.c_str(), + FsType, + FsMountOptions, WI_IsFlagClear(Flags, LXSS_IMPORT_DISTRO_FLAGS_NO_OOBE)); configuration = s_GetDistributionConfiguration(registration, DistributionName == nullptr); @@ -2432,7 +2444,7 @@ void LxssUserSessionImpl::_CreateLegacyRegistration(_In_ HKEY LxssKey, _In_ HAND const auto basePath = wsl::windows::common::filesystem::GetLegacyBasePath(UserToken); DistributionRegistration::Create( - LxssKey, LXSS_LEGACY_DISTRO_GUID, LXSS_LEGACY_INSTALL_NAME, LXSS_DISTRO_VERSION_LEGACY, basePath.c_str(), configFlags, defaultUid, nullptr, LXSS_VM_MODE_VHD_NAME, false); + LxssKey, LXSS_LEGACY_DISTRO_GUID, LXSS_LEGACY_INSTALL_NAME, LXSS_DISTRO_VERSION_LEGACY, basePath.c_str(), configFlags, defaultUid, nullptr, LXSS_VM_MODE_VHD_NAME, nullptr, nullptr, false); _SetDistributionInstalled(LxssKey, LXSS_LEGACY_DISTRO_GUID); } @@ -2458,6 +2470,7 @@ std::vector LxssUserSess return mounts; } +// TODO _Requires_lock_not_held_(m_instanceLock) std::shared_ptr LxssUserSessionImpl::_CreateInstance(_In_opt_ LPCGUID DistroGuid, _In_ ULONG Flags) { @@ -3991,6 +4004,8 @@ LxssUserSessionImpl::s_GetDistributionConfiguration(const DistributionRegistrati // Read the vhd file name and append to the base path. configuration.VhdFilePath = configuration.BasePath / Distro.Read(Property::VhdFileName); + configuration.FsType = Distro.Read(Property::FsType); + configuration.FsMountOptions = Distro.Read(Property::FsMountOptions); configuration.Flags = Distro.Read(Property::Flags); configuration.OsVersion = Distro.Read(Property::OsVersion).value_or(L""); diff --git a/src/windows/service/exe/LxssUserSession.h b/src/windows/service/exe/LxssUserSession.h index 6e2d41687..5f1e8185e 100644 --- a/src/windows/service/exe/LxssUserSession.h +++ b/src/windows/service/exe/LxssUserSession.h @@ -164,6 +164,8 @@ class DECLSPEC_UUID("a9b7a1b9-0671-405c-95f1-e0612cb4ce7e") LxssUserSession _In_ LPCWSTR TargetDirectory, _In_ ULONG Flags, _In_ ULONG64 VhdSize, + _In_ LPCWSTR FsType, + _In_ LPCWSTR FsMountOptions, _In_opt_ LPCWSTR PackageFamilyName, _Out_ LPWSTR* InstalledDistributionName, _Out_ LXSS_ERROR_INFO* Error, @@ -180,6 +182,8 @@ class DECLSPEC_UUID("a9b7a1b9-0671-405c-95f1-e0612cb4ce7e") LxssUserSession _In_ LPCWSTR TargetDirectory, _In_ ULONG Flags, _In_ ULONG64 VhdSize, + _In_ LPCWSTR FsType, + _In_ LPCWSTR FsMountOptions, _In_opt_ LPCWSTR PackageFamilyName, _Out_ LPWSTR* InstalledDistributionName, _Out_ LXSS_ERROR_INFO* Error, @@ -457,6 +461,8 @@ class LxssUserSessionImpl _In_ LPCWSTR TargetDirectory, _In_ ULONG Flags, _In_ ULONG64 VhdSize, + _In_ LPCWSTR FsType, + _In_ LPCWSTR FsMountOptions, _In_opt_ LPCWSTR PackageFamilyName, _Out_opt_ LPWSTR* InstalledDistributionName, _Out_ GUID* pDistroGuid); diff --git a/src/windows/service/exe/WslCoreVm.cpp b/src/windows/service/exe/WslCoreVm.cpp index 39552dd9c..f412dc1b0 100644 --- a/src/windows/service/exe/WslCoreVm.cpp +++ b/src/windows/service/exe/WslCoreVm.cpp @@ -1199,8 +1199,9 @@ std::shared_ptr WslCoreVm::CreateInstance( message->MountDeviceType = LxMiniInitMountDeviceTypeLun; message->DeviceId = lun; message->Flags = flags; - message.WriteString(message->FsTypeOffset, "ext4"); - message.WriteString(message->MountOptionsOffset, "discard,errors=remount-ro,data=ordered"); + // TODO: add configuration for fsType and mountOptions + message.WriteString(message->FsTypeOffset, Configuration.FsType); + message.WriteString(message->MountOptionsOffset, Configuration.FsMountOptions); message.WriteString(message->VmIdOffset, m_machineId); message.WriteString(message->DistributionNameOffset, Configuration.Name); message.WriteString(message->SharedMemoryRootOffset, sharedMemoryRoot); diff --git a/src/windows/service/inc/wslservice.idl b/src/windows/service/inc/wslservice.idl index c68ad7567..9f0c3f526 100644 --- a/src/windows/service/inc/wslservice.idl +++ b/src/windows/service/inc/wslservice.idl @@ -187,6 +187,8 @@ interface ILxssUserSession : IUnknown [in, unique] LPCWSTR TargetDirectory, [in] ULONG Flags, [in] ULONG64 VhdSize, + [in] LPCWSTR FsType, + [in] LPCWSTR FsMountOptions, [in, unique] LPCWSTR PackageFamilyName, [out] LPWSTR* InstalledDistributionName, [in, out] LXSS_ERROR_INFO* Error, @@ -201,6 +203,8 @@ interface ILxssUserSession : IUnknown [in, unique] LPCWSTR TargetDirectory, [in] ULONG Flags, [in] ULONG64 VhdSize, + [in] LPCWSTR FsType, + [in] LPCWSTR FsMountOptions, [in, unique] LPCWSTR PackageFamilyName, [out] LPWSTR* InstalledDistributionName, [in, out] LXSS_ERROR_INFO* Error, From 7dc89c5c0cb14bec72aea6c8a4cb40528052b502 Mon Sep 17 00:00:00 2001 From: artiga033 Date: Wed, 21 Jan 2026 16:27:22 +0800 Subject: [PATCH 02/21] fix --- src/windows/common/svccomm.cpp | 4 ++-- src/windows/common/svccomm.hpp | 4 ++-- src/windows/service/exe/DistributionRegistration.h | 4 ++-- src/windows/service/exe/LxssUserSession.cpp | 12 ++++++------ src/windows/service/exe/LxssUserSession.h | 12 ++++++------ src/windows/service/inc/wslservice.idl | 11 +++++++---- 6 files changed, 25 insertions(+), 22 deletions(-) diff --git a/src/windows/common/svccomm.cpp b/src/windows/common/svccomm.cpp index 8db1c8bb8..75a602353 100644 --- a/src/windows/common/svccomm.cpp +++ b/src/windows/common/svccomm.cpp @@ -914,8 +914,8 @@ std::pair wsl::windows::common::SvcComm::Reg _In_ LPCWSTR TargetDirectory, _In_ ULONG Flags, _In_ std::optional VhdSize, - _In_ LPCWSTR FsType, - _In_ LPCWSTR MountOptions, + _In_opt_ LPCWSTR FsType, + _In_opt_ LPCWSTR MountOptions, _In_opt_ LPCWSTR PackageFamilyName) const { ClientExecutionContext context; diff --git a/src/windows/common/svccomm.hpp b/src/windows/common/svccomm.hpp index e86dcea1f..25665044d 100644 --- a/src/windows/common/svccomm.hpp +++ b/src/windows/common/svccomm.hpp @@ -86,8 +86,8 @@ class SvcComm _In_ LPCWSTR TargetDirectory, _In_ ULONG Flags, _In_ std::optional VhdSize = std::nullopt, - _In_ LPCWSTR FsType = L"ext4", - _In_ LPCWSTR FsMountOptions = L"discard,errors=remount-ro,data=ordered", + _In_opt_ LPCWSTR FsType = nullptr, + _In_opt_ LPCWSTR FsMountOptions = nullptr, _In_opt_ LPCWSTR PackageFamilyName = nullptr) const; HRESULT diff --git a/src/windows/service/exe/DistributionRegistration.h b/src/windows/service/exe/DistributionRegistration.h index adeb337d4..81e3fb612 100644 --- a/src/windows/service/exe/DistributionRegistration.h +++ b/src/windows/service/exe/DistributionRegistration.h @@ -93,8 +93,8 @@ namespace Property { inline DistributionPropertyWithDefault PackageFamilyName{L"PackageFamilyName", L""}; inline DistributionPropertyWithDefault KernelCommandLine{L"KernelCommandLine", L""}; inline DistributionPropertyWithDefault VhdFileName{L"VhdFileName", LXSS_VM_MODE_VHD_NAME}; - inline DistributionPropertyWithDefault FsType{L"FsType", L"ext4"}; - inline DistributionPropertyWithDefault FsMountOptions{L"FsMountOptions", L"discard,errors=remount-ro,data=ordered"}; + inline DistributionPropertyWithDefault FsType{L"FsType", LXSS_DISTRO_DEFAULT_FS_TYPE}; + inline DistributionPropertyWithDefault FsMountOptions{L"FsMountOptions", LXSS_DISTRO_DEFAULT_FS_MOUNT_OPTIONS}; inline ExpectedProperty Name{L"DistributionName"}; inline ExpectedProperty BasePath{L"BasePath"}; inline DistributionProperty Flavor{L"Flavor"}; diff --git a/src/windows/service/exe/LxssUserSession.cpp b/src/windows/service/exe/LxssUserSession.cpp index cdb2db86a..a3fa5945e 100644 --- a/src/windows/service/exe/LxssUserSession.cpp +++ b/src/windows/service/exe/LxssUserSession.cpp @@ -383,8 +383,8 @@ HRESULT STDMETHODCALLTYPE LxssUserSession::RegisterDistribution( _In_ LPCWSTR TargetDirectory, _In_ ULONG Flags, _In_ ULONG64 VhdSize, - _In_ LPCWSTR FsType, - _In_ LPCWSTR FsMountOptions, + _In_opt_ LPCWSTR FsType, + _In_opt_ LPCWSTR FsMountOptions, _In_opt_ LPCWSTR PackageFamilyName, _Out_ LPWSTR* InstalledDistributionName, _Out_ LXSS_ERROR_INFO* Error, @@ -434,8 +434,8 @@ HRESULT STDMETHODCALLTYPE LxssUserSession::RegisterDistributionPipe( _In_ LPCWSTR TargetDirectory, _In_ ULONG Flags, _In_ ULONG64 VhdSize, - _In_ LPCWSTR FsType, - _In_ LPCWSTR FsMountOptions, + _In_opt_ LPCWSTR FsType, + _In_opt_ LPCWSTR FsMountOptions, _In_opt_ LPCWSTR PackageFamilyName, _Out_ LPWSTR* InstalledDistributionName, _Out_ LXSS_ERROR_INFO* Error, @@ -1358,8 +1358,8 @@ HRESULT LxssUserSessionImpl::RegisterDistribution( _In_ LPCWSTR TargetDirectory, _In_ ULONG Flags, _In_ ULONG64 VhdSize, - _In_ LPCWSTR FsType, - _In_ LPCWSTR FsMountOptions, + _In_opt_ LPCWSTR FsType, + _In_opt_ LPCWSTR FsMountOptions, _In_opt_ LPCWSTR PackageFamilyName, _Out_opt_ LPWSTR* InstalledDistributionName, _Out_ GUID* pDistroGuid) diff --git a/src/windows/service/exe/LxssUserSession.h b/src/windows/service/exe/LxssUserSession.h index 5f1e8185e..bc95c6eca 100644 --- a/src/windows/service/exe/LxssUserSession.h +++ b/src/windows/service/exe/LxssUserSession.h @@ -164,8 +164,8 @@ class DECLSPEC_UUID("a9b7a1b9-0671-405c-95f1-e0612cb4ce7e") LxssUserSession _In_ LPCWSTR TargetDirectory, _In_ ULONG Flags, _In_ ULONG64 VhdSize, - _In_ LPCWSTR FsType, - _In_ LPCWSTR FsMountOptions, + _In_opt_ LPCWSTR FsType, + _In_opt_ LPCWSTR FsMountOptions, _In_opt_ LPCWSTR PackageFamilyName, _Out_ LPWSTR* InstalledDistributionName, _Out_ LXSS_ERROR_INFO* Error, @@ -182,8 +182,8 @@ class DECLSPEC_UUID("a9b7a1b9-0671-405c-95f1-e0612cb4ce7e") LxssUserSession _In_ LPCWSTR TargetDirectory, _In_ ULONG Flags, _In_ ULONG64 VhdSize, - _In_ LPCWSTR FsType, - _In_ LPCWSTR FsMountOptions, + _In_opt_ LPCWSTR FsType, + _In_opt_ LPCWSTR FsMountOptions, _In_opt_ LPCWSTR PackageFamilyName, _Out_ LPWSTR* InstalledDistributionName, _Out_ LXSS_ERROR_INFO* Error, @@ -461,8 +461,8 @@ class LxssUserSessionImpl _In_ LPCWSTR TargetDirectory, _In_ ULONG Flags, _In_ ULONG64 VhdSize, - _In_ LPCWSTR FsType, - _In_ LPCWSTR FsMountOptions, + _In_opt_ LPCWSTR FsType, + _In_opt_ LPCWSTR FsMountOptions, _In_opt_ LPCWSTR PackageFamilyName, _Out_opt_ LPWSTR* InstalledDistributionName, _Out_ GUID* pDistroGuid); diff --git a/src/windows/service/inc/wslservice.idl b/src/windows/service/inc/wslservice.idl index 9f0c3f526..8c609e691 100644 --- a/src/windows/service/inc/wslservice.idl +++ b/src/windows/service/inc/wslservice.idl @@ -99,6 +99,9 @@ cpp_quote("#define LXSS_DISTRO_DEFAULT_ENVIRONMENT \"HOSTTYPE=x86_64\0LANG=en_US cpp_quote("#define LXSS_DISTRO_DEFAULT_KERNEL_COMMAND_LINE \"BOOT_IMAGE=/kernel init=/init\"") +cpp_quote("#define LXSS_DISTRO_DEFAULT_FS_TYPE L\"ext4\"") +cpp_quote("#define LXSS_DISTRO_DEFAULT_FS_MOUNT_OPTIONS L\"discard,errors=remount-ro,data=ordered\"") + cpp_quote("#define LXSS_DISTRO_FLAGS_ENABLE_INTEROP 0x1") cpp_quote("#define LXSS_DISTRO_FLAGS_APPEND_NT_PATH 0x2") cpp_quote("#define LXSS_DISTRO_FLAGS_ENABLE_DRIVE_MOUNTING 0x4") @@ -187,8 +190,8 @@ interface ILxssUserSession : IUnknown [in, unique] LPCWSTR TargetDirectory, [in] ULONG Flags, [in] ULONG64 VhdSize, - [in] LPCWSTR FsType, - [in] LPCWSTR FsMountOptions, + [in, unique] LPCWSTR FsType, + [in, unique] LPCWSTR FsMountOptions, [in, unique] LPCWSTR PackageFamilyName, [out] LPWSTR* InstalledDistributionName, [in, out] LXSS_ERROR_INFO* Error, @@ -203,8 +206,8 @@ interface ILxssUserSession : IUnknown [in, unique] LPCWSTR TargetDirectory, [in] ULONG Flags, [in] ULONG64 VhdSize, - [in] LPCWSTR FsType, - [in] LPCWSTR FsMountOptions, + [in, unique] LPCWSTR FsType, + [in, unique] LPCWSTR FsMountOptions, [in, unique] LPCWSTR PackageFamilyName, [out] LPWSTR* InstalledDistributionName, [in, out] LXSS_ERROR_INFO* Error, From e3ffc729a450161e31ee9d0b017d7de8d8dbe240 Mon Sep 17 00:00:00 2001 From: artiga033 Date: Tue, 20 Jan 2026 23:32:57 +0800 Subject: [PATCH 03/21] support import --- localization/strings/en-US/Resources.resw | 7 +++++++ localization/strings/zh-CN/Resources.resw | 7 +++++++ src/linux/init/main.cpp | 5 +++++ src/windows/common/WslClient.cpp | 14 +++++++++++++- src/windows/inc/wsl.h | 2 ++ 5 files changed, 34 insertions(+), 1 deletion(-) diff --git a/localization/strings/en-US/Resources.resw b/localization/strings/en-US/Resources.resw index ace4df40c..729249a63 100644 --- a/localization/strings/en-US/Resources.resw +++ b/localization/strings/en-US/Resources.resw @@ -558,6 +558,13 @@ Arguments for managing distributions in Windows Subsystem for Linux: Specifies that the provided file is a .vhd or .vhdx file, not a tar file. This operation makes a copy of the VHD file at the specified install location. + --fs-type + Specify the filesystem type to use for the distribution root. + Defaults to ext4. + + --fs-mount-options + Specify additional mount options for the filesystem. + --import-in-place <Distro> <FileName> Imports the specified VHD file as a new distribution. This virtual hard disk must be formatted with the ext4 filesystem type. diff --git a/localization/strings/zh-CN/Resources.resw b/localization/strings/zh-CN/Resources.resw index eb50631ff..0899315c4 100644 --- a/localization/strings/zh-CN/Resources.resw +++ b/localization/strings/zh-CN/Resources.resw @@ -564,6 +564,13 @@ 指定所提供的文件是 .vhd 还是 .vhdx 文件,而不是 tar 文件。 此操作在指定的安装位置创建 VHD 文件的副本。 + --fs-type + 指定用于分发版根目录的文件系统类型。 + 默认为 ext4。 + + --fs-mount-options + 指定根目录文件系统的其他装载选项。 + --import-in-place <Distro> <FileName> 将指定的 VHD 文件作为新发行版导入。 必须使用 ext4 文件系统类型设置此虚拟硬盘的格式。 diff --git a/src/linux/init/main.cpp b/src/linux/init/main.cpp index 843b1942a..dab97c5f0 100644 --- a/src/linux/init/main.cpp +++ b/src/linux/init/main.cpp @@ -938,6 +938,11 @@ try { CommandLine = std::format("/usr/sbin/mkfs.btrfs '{}'", DevicePath); } + else + { + LOG_ERROR("Unsupported filesystem type: {}", FsType_s); + return -1; + } if (UtilExecCommandLine(CommandLine.c_str(), nullptr) < 0) { return -1; diff --git a/src/windows/common/WslClient.cpp b/src/windows/common/WslClient.cpp index 34ca5756b..4eea28f9c 100644 --- a/src/windows/common/WslClient.cpp +++ b/src/windows/common/WslClient.cpp @@ -319,12 +319,16 @@ int ImportDistribution(_In_ std::wstring_view commandLine) std::filesystem::path filePath; ULONG flags = LXSS_IMPORT_DISTRO_FLAGS_NO_OOBE; DWORD version = LXSS_WSL_VERSION_DEFAULT; + std::optional fsType; + std::optional fsMountOptions; parser.AddPositionalArgument(name, 0); parser.AddPositionalArgument(AbsolutePath(installPath), 1); parser.AddPositionalArgument(filePath, 2); parser.AddArgument(WslVersion(version), WSL_IMPORT_ARG_VERSION); parser.AddArgument(SetFlag{flags}, WSL_IMPORT_ARG_VHD); + parser.AddArgument(fsType, WSL_IMPORT_ARG_FS_TYPE); + parser.AddArgument(fsMountOptions, WSL_IMPORT_ARG_FS_MOUNT_OPTIONS); parser.Parse(); @@ -385,7 +389,15 @@ int ImportDistribution(_In_ std::wstring_view commandLine) { wsl::windows::common::HandleConsoleProgressBar progressBar(fileHandle, Localization::MessageImportProgress()); wsl::windows::common::SvcComm service; - service.RegisterDistribution(name, version, fileHandle, installPath->c_str(), flags); + service.RegisterDistribution( + name, + version, + fileHandle, + installPath->c_str(), + flags, + std::nullopt, + fsType.has_value() ? fsType->c_str() : nullptr, + fsMountOptions.has_value() ? fsMountOptions->c_str() : nullptr); } directory_cleanup.release(); diff --git a/src/windows/inc/wsl.h b/src/windows/inc/wsl.h index b5516bb69..2e81feadd 100644 --- a/src/windows/inc/wsl.h +++ b/src/windows/inc/wsl.h @@ -29,6 +29,8 @@ Module Name: #define WSL_EXPORT_ARG_VHD_OPTION L"--vhd" #define WSL_HELP_ARG L"--help" #define WSL_IMPORT_ARG L"--import" +#define WSL_IMPORT_ARG_FS_MOUNT_OPTIONS L"--fs-mount-options" +#define WSL_IMPORT_ARG_FS_TYPE L"--fs-type" #define WSL_IMPORT_ARG_STDIN L"-" #define WSL_IMPORT_ARG_VERSION L"--version" #define WSL_IMPORT_ARG_VHD L"--vhd" From 0a63ea63badbef14ef2394026af9b3ec1cb9f8cb Mon Sep 17 00:00:00 2001 From: artiga033 Date: Wed, 21 Jan 2026 18:01:44 +0800 Subject: [PATCH 04/21] don't check einval because invalid mount options also return this --- src/windows/service/exe/WslCoreInstance.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/windows/service/exe/WslCoreInstance.cpp b/src/windows/service/exe/WslCoreInstance.cpp index 74fe3168d..6b32d3c0b 100644 --- a/src/windows/service/exe/WslCoreInstance.cpp +++ b/src/windows/service/exe/WslCoreInstance.cpp @@ -60,7 +60,7 @@ WslCoreInstance::WslCoreInstance( if (result.Result != 0) { // N.B. EUCLEAN (117) can be returned if the disk's journal is corrupted. - if ((result.Result == EINVAL || result.Result == 117) && result.FailureStep == LxInitCreateInstanceStepMountDisk) + if ((result.Result == 117) && result.FailureStep == LxInitCreateInstanceStepMountDisk) { THROW_HR(WSL_E_DISK_CORRUPTED); } From 4986ddbfcce4e9a726b461ed98905944463d6592 Mon Sep 17 00:00:00 2001 From: artiga033 Date: Wed, 21 Jan 2026 20:30:13 +0800 Subject: [PATCH 05/21] support for a default btrfs subvol --- src/linux/init/main.cpp | 97 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 90 insertions(+), 7 deletions(-) diff --git a/src/linux/init/main.cpp b/src/linux/init/main.cpp index dab97c5f0..99273e632 100644 --- a/src/linux/init/main.cpp +++ b/src/linux/init/main.cpp @@ -137,6 +137,7 @@ int EnableInterface(int Socket, const char* Name); int ExportToSocket(const char* Source, int Socket, int ErrorSocket, unsigned int flags); int FormatDevice(unsigned int Lun, const char* FsType); +int CreateBtrfsSubvolumeOnDevice(unsigned int Lun, const char* MountOptions); std::string GetLunDeviceName(unsigned int Lun); @@ -907,8 +908,8 @@ int FormatDevice(unsigned int Lun, const char* FsType) Routine Description: - This routine formats the specified SCSI device with the ext4 file system. - N.B. The group size was chosen based on the best practices for Linux VHDs: + This routine formats the specified SCSI device with the file system. + N.B. The ext4 group size was chosen based on the best practices for Linux VHDs: https://docs.microsoft.com/en-us/windows-server/virtualization/hyper-v/best-practices-for-running-linux-on-hyper-v Arguments: @@ -927,20 +928,25 @@ try std::string DevicePath = GetLunDevicePath(Lun); WaitForBlockDevice(DevicePath.c_str()); - + + if (FsType == nullptr) + { + FsType = "ext4"; + } + std::string CommandLine; - std::string FsType_s = std::string(FsType); - if (FsType_s == "ext4") + if (strcmp(FsType, "ext4") == 0) { CommandLine = std::format("/usr/sbin/mkfs.ext4 -G 4096 '{}'", DevicePath); } - else if (FsType_s == "btrfs") + else if (strcmp(FsType, "btrfs") == 0) { CommandLine = std::format("/usr/sbin/mkfs.btrfs '{}'", DevicePath); } else { - LOG_ERROR("Unsupported filesystem type: {}", FsType_s); + LOG_ERROR("Unsupported filesystem type: {}", FsType); + errno = ENOSYS; return -1; } if (UtilExecCommandLine(CommandLine.c_str(), nullptr) < 0) @@ -952,6 +958,77 @@ try } CATCH_RETURN_ERRNO() +int CreateBtrfsSubvolumeOnDevice(unsigned int Lun, const char* MountOptions) +/*++ +Routine Description: + + This routine creates a btrfs subvolume on the specified SCSI device. No-op if there is no subvolume name in the mount options or the subvolume already exists. +Arguments: + Lun - Supplies the LUN number of the SCSI device. + MountOptions - The mount options to use when mounting the device. Subvolume name is extracted from it. +Return Value: + 0 on success, < 0 on failure. +--*/ +try +{ + if (MountOptions == nullptr) + { + return 0; + } + + std::string_view options(MountOptions); + std::string_view subvolName; + + size_t pos = 0; + while (pos < options.size()) + { + size_t end = options.find(',', pos); + if (end == std::string_view::npos) + { + end = options.size(); + } + + std::string_view option = options.substr(pos, end - pos); + if (option.starts_with("subvol=")) + { + subvolName = option.substr(7); // Skip "subvol=" + break; + } + + pos = end + 1; + } + + if (subvolName.empty()) + { + return 0; + } + + std::string DevicePath = GetLunDevicePath(Lun); + std::string TempMountPath; + THROW_LAST_ERROR_IF(CreateTempDirectory("/tmp", TempMountPath) < 0); + + auto unmountOnExit = wil::scope_exit([&TempMountPath]() { + umount(TempMountPath.c_str()); + rmdir(TempMountPath.c_str()); + }); + + THROW_LAST_ERROR_IF(UtilMount(DevicePath.c_str(), TempMountPath.c_str(), "btrfs", 0, nullptr, c_defaultRetryTimeout) < 0); + + std::string SubvolPath = std::format("{}/{}", TempMountPath, subvolName); + + struct stat st; + if (stat(SubvolPath.c_str(), &st) == 0) + { + return 0; + } + + std::string CommandLine = std::format("/usr/sbin/btrfs subvolume create '{}'", SubvolPath); + THROW_LAST_ERROR_IF(UtilExecCommandLine(CommandLine.c_str(), nullptr) < 0); + + return 0; +} +CATCH_RETURN_ERRNO() + std::string GetLunDeviceName(unsigned int Lun) /*++ @@ -2761,6 +2838,12 @@ void ProcessImportExportMessage(gsl::span Buffer, wsl::shared::Socket THROW_LAST_ERROR_IF(FormatDevice(Message->DeviceId, FsType) < 0); } + if (FsType != nullptr && strcmp(FsType, "btrfs") == 0) + { + // create the subvolume if specified in mount options + CreateBtrfsSubvolumeOnDevice(Message->DeviceId, MountOptions); + } + THROW_LAST_ERROR_IF(MountDevice(Message->MountDeviceType, Message->DeviceId, DISTRO_PATH, FsType, Message->Flags, MountOptions) < 0); Result = 0; From dce72d3d8dfa0007fb6a9a3d55e2e9e8f4cc8cfb Mon Sep 17 00:00:00 2001 From: artiga033 Date: Wed, 21 Jan 2026 21:47:59 +0800 Subject: [PATCH 06/21] use proper default mount options for non-default fs --- src/windows/service/exe/DistributionRegistration.cpp | 10 ++++++++++ src/windows/service/inc/wslservice.idl | 5 ++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/windows/service/exe/DistributionRegistration.cpp b/src/windows/service/exe/DistributionRegistration.cpp index e42a5ec0b..02125e563 100644 --- a/src/windows/service/exe/DistributionRegistration.cpp +++ b/src/windows/service/exe/DistributionRegistration.cpp @@ -132,6 +132,16 @@ DistributionRegistration DistributionRegistration::Create( { distribution.Write(Property::FsMountOptions, FsMountOptions); } + else if (ARGUMENT_PRESENT(FsType) && wcscmp(FsType, LXSS_DISTRO_DEFAULT_FS_TYPE) != 0) + { + // FsType-specific default mount options + if (wcscmp(FsType, L"ext4") == 0) + distribution.Write(Property::FsMountOptions, LXSS_DISTRO_DEFAULT_FS_MOUNT_OPTIONS_EXT4); + else if (wcscmp(FsType, L"btrfs") == 0) + distribution.Write(Property::FsMountOptions, LXSS_DISTRO_DEFAULT_FS_MOUNT_OPTIONS_BTRFS); + else if (wcscmp(FsType, L"xfs") == 0) + distribution.Write(Property::FsMountOptions, LXSS_DISTRO_DEFAULT_FS_MOUNT_OPTIONS_XFS); + } // Dismiss the scope exit member so the key is persisted. cleanup.release(); diff --git a/src/windows/service/inc/wslservice.idl b/src/windows/service/inc/wslservice.idl index 8c609e691..d5dbd7bc5 100644 --- a/src/windows/service/inc/wslservice.idl +++ b/src/windows/service/inc/wslservice.idl @@ -100,7 +100,10 @@ cpp_quote("#define LXSS_DISTRO_DEFAULT_ENVIRONMENT \"HOSTTYPE=x86_64\0LANG=en_US cpp_quote("#define LXSS_DISTRO_DEFAULT_KERNEL_COMMAND_LINE \"BOOT_IMAGE=/kernel init=/init\"") cpp_quote("#define LXSS_DISTRO_DEFAULT_FS_TYPE L\"ext4\"") -cpp_quote("#define LXSS_DISTRO_DEFAULT_FS_MOUNT_OPTIONS L\"discard,errors=remount-ro,data=ordered\"") +cpp_quote("#define LXSS_DISTRO_DEFAULT_FS_MOUNT_OPTIONS_EXT4 L\"discard,errors=remount-ro,data=ordered\"") +cpp_quote("#define LXSS_DISTRO_DEFAULT_FS_MOUNT_OPTIONS_BTRFS L\"discard\"") +cpp_quote("#define LXSS_DISTRO_DEFAULT_FS_MOUNT_OPTIONS_XFS L\"discard\"") +cpp_quote("#define LXSS_DISTRO_DEFAULT_FS_MOUNT_OPTIONS LXSS_DISTRO_DEFAULT_FS_MOUNT_OPTIONS_EXT4") cpp_quote("#define LXSS_DISTRO_FLAGS_ENABLE_INTEROP 0x1") cpp_quote("#define LXSS_DISTRO_FLAGS_APPEND_NT_PATH 0x2") From 36d0243dd823490c7edd9389dc127a19b143e0b0 Mon Sep 17 00:00:00 2001 From: artiga033 Date: Wed, 21 Jan 2026 22:26:00 +0800 Subject: [PATCH 07/21] complete support for xfs --- src/linux/init/main.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/linux/init/main.cpp b/src/linux/init/main.cpp index 99273e632..1c8b4810b 100644 --- a/src/linux/init/main.cpp +++ b/src/linux/init/main.cpp @@ -912,6 +912,7 @@ Routine Description: N.B. The ext4 group size was chosen based on the best practices for Linux VHDs: https://docs.microsoft.com/en-us/windows-server/virtualization/hyper-v/best-practices-for-running-linux-on-hyper-v + N.B. The xfs data section options (-d) is also determined based on the VHD sector size of 1MB, as suggested in the link above. Arguments: Lun - Supplies the LUN number of the SCSI device. @@ -928,12 +929,12 @@ try std::string DevicePath = GetLunDevicePath(Lun); WaitForBlockDevice(DevicePath.c_str()); - + if (FsType == nullptr) { FsType = "ext4"; } - + std::string CommandLine; if (strcmp(FsType, "ext4") == 0) { @@ -943,6 +944,10 @@ try { CommandLine = std::format("/usr/sbin/mkfs.btrfs '{}'", DevicePath); } + else if (strcmp(FsType, "xfs") == 0) + { + CommandLine = std::format("/usr/sbin/mkfs.xfs -s size=4096 -d su=1m,sw=1 '{}'", DevicePath); + } else { LOG_ERROR("Unsupported filesystem type: {}", FsType); @@ -958,16 +963,13 @@ try } CATCH_RETURN_ERRNO() -int CreateBtrfsSubvolumeOnDevice(unsigned int Lun, const char* MountOptions) +int CreateBtrfsSubvolumeOnDevice(unsigned int Lun, const char* MountOptions) /*++ Routine Description: - This routine creates a btrfs subvolume on the specified SCSI device. No-op if there is no subvolume name in the mount options or the subvolume already exists. -Arguments: - Lun - Supplies the LUN number of the SCSI device. - MountOptions - The mount options to use when mounting the device. Subvolume name is extracted from it. -Return Value: - 0 on success, < 0 on failure. + This routine creates a btrfs subvolume on the specified SCSI device. No-op if there is no subvolume name in the mount options +or the subvolume already exists. Arguments: Lun - Supplies the LUN number of the SCSI device. MountOptions - The mount options to +use when mounting the device. Subvolume name is extracted from it. Return Value: 0 on success, < 0 on failure. --*/ try { From d3bcb4d3b8a8421f50e58b2fec2775d82ad4df29 Mon Sep 17 00:00:00 2001 From: artiga033 Date: Sat, 31 Jan 2026 13:00:24 +0800 Subject: [PATCH 08/21] cli arg for set fs mount options --- localization/strings/en-US/Resources.resw | 5 ++- localization/strings/zh-CN/Resources.resw | 5 ++- src/windows/common/WslClient.cpp | 8 ++++- src/windows/common/svccomm.cpp | 7 +++++ src/windows/common/svccomm.hpp | 2 ++ src/windows/inc/wsl.h | 1 + src/windows/service/exe/LxssUserSession.cpp | 35 +++++++++++++++++++++ src/windows/service/exe/LxssUserSession.h | 11 +++++++ src/windows/service/inc/wslservice.idl | 5 +++ 9 files changed, 76 insertions(+), 3 deletions(-) diff --git a/localization/strings/en-US/Resources.resw b/localization/strings/en-US/Resources.resw index 729249a63..c0745589a 100644 --- a/localization/strings/en-US/Resources.resw +++ b/localization/strings/en-US/Resources.resw @@ -483,6 +483,9 @@ Arguments for managing Windows Subsystem for Linux: --resize <MemoryString> Resize the disk of the distribution to the specified size. + --set-fs-mount-options <Options> + Set the filesystem mount options for the distribution root. + --mount <Disk> Attaches and mounts a physical or virtual disk in all WSL 2 distributions. @@ -608,7 +611,7 @@ Arguments for managing distributions in Windows Subsystem for Linux: "}{Locked="--from-file "}{Locked="--legacy "}{Locked="--location "}{Locked="--name "}{Locked="--no-distribution "}{Locked="--no-launch,"}{Locked="--version "}{Locked="--vhd-size "}{Locked="--web-download -"}{Locked="--manage "}{Locked="--move "}{Locked="--set-sparse,"}{Locked="--set-default-user "}{Locked="--resize "}{Locked="--mount "}{Locked="--vhd +"}{Locked="--manage "}{Locked="--move "}{Locked="--set-sparse,"}{Locked="--set-default-user "}{Locked="--resize "}{Locked="--set-fs-mount-options "}{Locked="--mount "}{Locked="--vhd "}{Locked="--bare "}{Locked="--name "}{Locked="--type "}{Locked="--options "}{Locked="--partition "}{Locked="--set-default-version "}{Locked="--shutdown "}{Locked="--force diff --git a/localization/strings/zh-CN/Resources.resw b/localization/strings/zh-CN/Resources.resw index 0899315c4..d20f0450a 100644 --- a/localization/strings/zh-CN/Resources.resw +++ b/localization/strings/zh-CN/Resources.resw @@ -489,6 +489,9 @@ --resize <MemoryString> 将发行版的磁盘大小调整为指定大小。 + --set-fs-mount-options <Options> + 设置发行版根目录的文件系统挂载选项。 + --mount <Disk> 在所有 WSL 2 发行版中附加和装载物理磁盘或虚拟磁盘。 @@ -614,7 +617,7 @@ "}{Locked="--from-file "}{Locked="--legacy "}{Locked="--location "}{Locked="--name "}{Locked="--no-distribution "}{Locked="--no-launch,"}{Locked="--version "}{Locked="--vhd-size "}{Locked="--web-download -"}{Locked="--manage "}{Locked="--move "}{Locked="--set-sparse,"}{Locked="--set-default-user "}{Locked="--resize "}{Locked="--mount "}{Locked="--vhd +"}{Locked="--manage "}{Locked="--move "}{Locked="--set-sparse,"}{Locked="--set-default-user "}{Locked="--resize "}{Locked="--set-fs-mount-options "}{Locked="--mount "}{Locked="--vhd "}{Locked="--bare "}{Locked="--name "}{Locked="--type "}{Locked="--options "}{Locked="--partition "}{Locked="--set-default-version "}{Locked="--shutdown "}{Locked="--force diff --git a/src/windows/common/WslClient.cpp b/src/windows/common/WslClient.cpp index 4eea28f9c..239a68cb2 100644 --- a/src/windows/common/WslClient.cpp +++ b/src/windows/common/WslClient.cpp @@ -909,6 +909,7 @@ int Manage(_In_ std::wstring_view commandLine) std::optional move; std::optional defaultUser; std::optional resize; + std::optional fsMountOptions; bool allowUnsafe = false; ArgumentParser parser(std::wstring{commandLine}, WSL_BINARY_NAME, 0); @@ -917,6 +918,7 @@ int Manage(_In_ std::wstring_view commandLine) parser.AddArgument(AbsolutePath(move), WSL_MANAGE_ARG_MOVE_OPTION_LONG, WSL_MANAGE_ARG_MOVE_OPTION); parser.AddArgument(defaultUser, WSL_MANAGE_ARG_SET_DEFAULT_USER_OPTION_LONG); parser.AddArgument(SizeString(resize), WSL_MANAGE_ARG_RESIZE_OPTION_LONG, WSL_MANAGE_ARG_RESIZE_OPTION); + parser.AddArgument(fsMountOptions, WSL_MANAGE_ARG_SET_FS_MOUNT_OPTIONS_LONG); parser.AddArgument(allowUnsafe, WSL_MANAGE_ARG_ALLOW_UNSAFE); parser.Parse(); @@ -925,7 +927,7 @@ int Manage(_In_ std::wstring_view commandLine) wsl::windows::common::SvcComm service; auto distroGuid = service.GetDistributionId(distribution); - if (sparse.has_value() + move.has_value() + defaultUser.has_value() + resize.has_value() != 1) + if (sparse.has_value() + move.has_value() + defaultUser.has_value() + resize.has_value() + fsMountOptions.has_value() != 1) { THROW_HR(WSL_E_INVALID_USAGE); } @@ -972,6 +974,10 @@ int Manage(_In_ std::wstring_view commandLine) { THROW_IF_FAILED(service.ResizeDistribution(&distroGuid, resize.value())); } + else if (fsMountOptions) + { + service.SetFsMountOptions(&distroGuid, fsMountOptions->c_str()); + } wsl::windows::common::wslutil::PrintSystemError(ERROR_SUCCESS); return 0; diff --git a/src/windows/common/svccomm.cpp b/src/windows/common/svccomm.cpp index 75a602353..a8e8e58c1 100644 --- a/src/windows/common/svccomm.cpp +++ b/src/windows/common/svccomm.cpp @@ -988,6 +988,13 @@ wsl::windows::common::SvcComm::SetSparse(_In_ LPCGUID DistroGuid, _In_ BOOL Spar RETURN_HR(m_userSession->SetSparse(DistroGuid, Sparse, AllowUnsafe, context.OutError())); } +void wsl::windows::common::SvcComm::SetFsMountOptions(_In_ LPCGUID DistroGuid, _In_ LPCWSTR FsMountOptions) const +{ + ClientExecutionContext context; + + THROW_IF_FAILED(m_userSession->SetFsMountOptions(DistroGuid, FsMountOptions, context.OutError())); +} + HRESULT wsl::windows::common::SvcComm::ResizeDistribution(_In_ LPCGUID DistroGuid, _In_ ULONG64 NewSize) const { diff --git a/src/windows/common/svccomm.hpp b/src/windows/common/svccomm.hpp index 25665044d..2b0dc820e 100644 --- a/src/windows/common/svccomm.hpp +++ b/src/windows/common/svccomm.hpp @@ -98,6 +98,8 @@ class SvcComm HRESULT SetSparse(_In_ LPCGUID DistroGuid, _In_ BOOL Sparse, _In_ BOOL AllowUnsafe) const; + void SetFsMountOptions(_In_ LPCGUID DistroGuid, _In_ LPCWSTR FsMountOptions) const; + HRESULT SetVersion(_In_ LPCGUID DistroGuid, _In_ ULONG Version) const; diff --git a/src/windows/inc/wsl.h b/src/windows/inc/wsl.h index 2e81feadd..2a00090b5 100644 --- a/src/windows/inc/wsl.h +++ b/src/windows/inc/wsl.h @@ -79,6 +79,7 @@ Module Name: #define WSL_MANAGE_ARG_SET_SPARSE_OPTION L's' #define WSL_MANAGE_ARG_SET_SPARSE_OPTION_LONG L"--set-sparse" #define WSL_MANAGE_ARG_SET_DEFAULT_USER_OPTION_LONG L"--set-default-user" +#define WSL_MANAGE_ARG_SET_FS_MOUNT_OPTIONS_LONG L"--set-fs-mount-options" #define WSL_MOUNT_ARG L"--mount" #define WSL_MOUNT_ARG_VHD_OPTION_LONG L"--vhd" #define WSL_MOUNT_ARG_BARE_OPTION_LONG L"--bare" diff --git a/src/windows/service/exe/LxssUserSession.cpp b/src/windows/service/exe/LxssUserSession.cpp index a3fa5945e..a9498b7e6 100644 --- a/src/windows/service/exe/LxssUserSession.cpp +++ b/src/windows/service/exe/LxssUserSession.cpp @@ -486,6 +486,18 @@ try } CATCH_RETURN() +HRESULT STDMETHODCALLTYPE LxssUserSession::SetFsMountOptions(_In_ LPCGUID DistroGuid, _In_ LPCWSTR FsMountOptions, _Out_ LXSS_ERROR_INFO* Error) +try +{ + ServiceExecutionContext context(Error); + + const auto session = m_session.lock(); + RETURN_HR_IF(RPC_E_DISCONNECTED, !session); + + return session->SetFsMountOptions(DistroGuid, FsMountOptions); +} +CATCH_RETURN() + HRESULT STDMETHODCALLTYPE LxssUserSession::ResizeDistribution(_In_ LPCGUID DistroGuid, _In_ HANDLE OutputHandle, _In_ ULONG64 NewSize, _Out_ LXSS_ERROR_INFO* Error) try { @@ -1768,6 +1780,29 @@ try } CATCH_RETURN() +HRESULT LxssUserSessionImpl::SetFsMountOptions(_In_ LPCGUID DistroGuid, _In_ LPCWSTR FsMountOptions) +try +{ + ExecutionContext context(Context::ConfigureDistro); + + WSL_LOG("SetFsMountOptions", TraceLoggingValue(FsMountOptions, "FsMountOptions")); + + const wil::unique_hkey lxssKey = s_OpenLxssUserKey(); + std::lock_guard lock(m_instanceLock); + + // Ensure the distribution exists. + auto distribution = DistributionRegistration::Open(lxssKey.get(), *DistroGuid); + + // Write the new mount options. + distribution.Write(Property::FsMountOptions, FsMountOptions); + + // Terminate the distribution so the new settings will take effect. + _TerminateInstanceInternal(&distribution.Id(), false); + + return S_OK; +} +CATCH_RETURN() + HRESULT LxssUserSessionImpl::ResizeDistribution(_In_ LPCGUID DistroGuid, _In_ HANDLE OutputHandle, _In_ ULONG64 NewSize) try { diff --git a/src/windows/service/exe/LxssUserSession.h b/src/windows/service/exe/LxssUserSession.h index bc95c6eca..4702d707b 100644 --- a/src/windows/service/exe/LxssUserSession.h +++ b/src/windows/service/exe/LxssUserSession.h @@ -204,6 +204,11 @@ class DECLSPEC_UUID("a9b7a1b9-0671-405c-95f1-e0612cb4ce7e") LxssUserSession /// IFACEMETHOD(SetSparse)(_In_ LPCGUID DistroGuid, _In_ BOOLEAN Sparse, _In_ BOOLEAN AllowUnsafe, _Out_ LXSS_ERROR_INFO* Error) override; + /// + /// Sets the filesystem mount options for a distribution. + /// + IFACEMETHOD(SetFsMountOptions)(_In_ LPCGUID DistroGuid, _In_ LPCWSTR FsMountOptions, _Out_ LXSS_ERROR_INFO* Error) override; + /// /// Sets the version for a distribution. /// @@ -485,6 +490,12 @@ class LxssUserSessionImpl HRESULT SetSparse(_In_ LPCGUID DistroGuid, _In_ BOOLEAN Sparse, _In_ BOOLEAN AllowUnsafe); + /// + /// Sets the filesystem mount options for a distribution. + /// + HRESULT + SetFsMountOptions(_In_ LPCGUID DistroGuid, _In_ LPCWSTR FsMountOptions); + /// /// Sets the version for a distribution. /// diff --git a/src/windows/service/inc/wslservice.idl b/src/windows/service/inc/wslservice.idl index d5dbd7bc5..627ce54bc 100644 --- a/src/windows/service/inc/wslservice.idl +++ b/src/windows/service/inc/wslservice.idl @@ -266,6 +266,11 @@ interface ILxssUserSession : IUnknown [in] BOOLEAN AllowUnsafe, [in, out] LXSS_ERROR_INFO* Error); + HRESULT SetFsMountOptions( + [in] LPCGUID DistroGuid, + [in] LPCWSTR FsMountOptions, + [in, out] LXSS_ERROR_INFO* Error); + HRESULT EnumerateDistributions( [out] ULONG *DistributionCount, [out, size_is(, *DistributionCount)] LXSS_ENUMERATE_INFO **Distributions, From 268c176887aad231117c7f1bf3de29df2dd67ec5 Mon Sep 17 00:00:00 2001 From: artiga033 Date: Sat, 31 Jan 2026 18:42:25 +0800 Subject: [PATCH 09/21] update localization --- localization/strings/cs-CZ/Resources.resw | 25 +++++++++++-- localization/strings/da-DK/Resources.resw | 25 +++++++++++-- localization/strings/de-DE/Resources.resw | 29 ++++++++++++--- localization/strings/en-GB/Resources.resw | 25 +++++++++++-- localization/strings/en-US/Resources.resw | 6 ++-- localization/strings/es-ES/Resources.resw | 25 +++++++++++-- localization/strings/fi-FI/Resources.resw | 25 +++++++++++-- localization/strings/fr-FR/Resources.resw | 25 +++++++++++-- localization/strings/hu-HU/Resources.resw | 27 +++++++++++--- localization/strings/it-IT/Resources.resw | 25 +++++++++++-- localization/strings/ja-JP/Resources.resw | 25 +++++++++++-- localization/strings/ko-KR/Resources.resw | 26 ++++++++++++-- localization/strings/nb-NO/Resources.resw | 25 +++++++++++-- localization/strings/nl-NL/Resources.resw | 25 +++++++++++-- localization/strings/pl-PL/Resources.resw | 25 +++++++++++-- localization/strings/pt-BR/Resources.resw | 25 +++++++++++-- localization/strings/pt-PT/Resources.resw | 25 +++++++++++-- localization/strings/ru-RU/Resources.resw | 25 +++++++++++-- localization/strings/sv-SE/Resources.resw | 25 +++++++++++-- localization/strings/tr-TR/Resources.resw | 25 +++++++++++-- localization/strings/zh-CN/Resources.resw | 6 ++-- localization/strings/zh-TW/Resources.resw | 44 ++++++++++++++++++----- 22 files changed, 466 insertions(+), 72 deletions(-) diff --git a/localization/strings/cs-CZ/Resources.resw b/localization/strings/cs-CZ/Resources.resw index ce5b44f5a..b228dbc24 100644 --- a/localization/strings/cs-CZ/Resources.resw +++ b/localization/strings/cs-CZ/Resources.resw @@ -1,4 +1,4 @@ - +