Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 2 additions & 4 deletions src/windows/common/WslClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -504,10 +504,8 @@ int Install(_In_ std::wstring_view commandLine)
E_INVALIDARG, Localization::MessageArgumentsNotValidTogether(WSL_INSTALL_ARG_NO_DISTRIBUTION_OPTION, WSL_INSTALL_ARG_DIST_OPTION_LONG));
}

if (fixedVhd && !vhdSize.has_value())
{
THROW_HR_WITH_USER_ERROR(E_INVALIDARG, Localization::MessageArgumentNotValidWithout(WSL_INSTALL_ARG_FIXED_VHD, WSL_INSTALL_ARG_VHD_SIZE));
}
// Note: Validation for --fixed-vhd now allows it without --vhd-size if defaultVhdSize is set in .wslconfig.
// The service will handle the validation and application of defaults.

// A distribution to be installed can be specified in three ways:
// wsl.exe --install --distribution Ubuntu
Expand Down
1 change: 1 addition & 0 deletions src/windows/common/WslCoreConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ void wsl::core::Config::ParseConfigFile(_In_opt_ LPCWSTR ConfigFilePath, _In_opt
ConfigKey(ConfigSetting::DnsProxy, EnableDnsProxy),
ConfigKey(ConfigSetting::SafeMode, EnableSafeMode),
ConfigKey(ConfigSetting::DefaultVhdSize, MemoryString(VhdSizeBytes)),
ConfigKey(ConfigSetting::DefaultVhdType, wsl::core::VhdTypes, VhdDefaultType),
ConfigKey(ConfigSetting::CrashDumpFolder, CrashDumpFolder),
ConfigKey(ConfigSetting::MaxCrashDumpCount, MaxCrashDumpCount),
ConfigKey(ConfigSetting::DistributionInstallPath, DefaultDistributionLocation),
Expand Down
27 changes: 26 additions & 1 deletion src/windows/common/WslCoreConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Module Name:
T_VALUE(c, LoadDefaultKernelModules), T_PRESENT(c, LoadKernelModulesPresence), T_VALUE(c, MaximumMemorySizeBytes), \
T_VALUE(c, MaximumProcessorCount), T_ENUM(c, MemoryReclaim), T_VALUE(c, MemorySizeBytes), T_VALUE(c, MountDeviceTimeout), \
T_ENUM(c, NetworkingMode), T_VALUE(c, ProcessorCount), T_SET(c, SwapFilePath), T_VALUE(c, SwapSizeBytes), \
T_SET(c, SystemDistroPath), T_VALUE(c, VhdSizeBytes), T_VALUE(c, VmIdleTimeout), T_SET(c, VmSwitch)
T_SET(c, SystemDistroPath), T_VALUE(c, VhdSizeBytes), T_ENUM(c, VhdDefaultType), T_VALUE(c, VmIdleTimeout), T_SET(c, VmSwitch)

namespace wsl::core {
constexpr auto ToString(ConfigKeyPresence key)
Expand Down Expand Up @@ -80,6 +80,29 @@ const std::map<std::string, MemoryReclaimMode, shared::string::CaseInsensitiveCo
{ToString(MemoryReclaimMode::DropCache), MemoryReclaimMode::DropCache},
{ToString(MemoryReclaimMode::Disabled), MemoryReclaimMode::Disabled}};

enum class VhdType
{
Dynamic,
Fixed
};

constexpr auto ToString(VhdType type)
{
switch (type)
{
case VhdType::Dynamic:
return "Dynamic";
case VhdType::Fixed:
return "Fixed";
default:
return "Invalid";
}
}

const std::map<std::string, VhdType, shared::string::CaseInsensitiveCompare> VhdTypes = {
{ToString(VhdType::Dynamic), VhdType::Dynamic},
{ToString(VhdType::Fixed), VhdType::Fixed}};

// N.B. These enum values are also used in InTune ADMX templates, if entries are added or removed ensure that existing
// values are not changed.
enum NetworkingMode
Expand Down Expand Up @@ -266,6 +289,7 @@ namespace ConfigSetting {
static constexpr auto DnsProxy = "wsl2.dnsProxy";
static constexpr auto SafeMode = "wsl2.safeMode";
static constexpr auto DefaultVhdSize = "wsl2.defaultVhdSize";
static constexpr auto DefaultVhdType = "wsl2.defaultVhdType";
static constexpr auto CrashDumpFolder = "wsl2.crashDumpFolder";
static constexpr auto MaxCrashDumpCount = "wsl2.maxCrashDumpCount";
static constexpr auto DistributionInstallPath = "general.distributionInstallPath";
Expand Down Expand Up @@ -363,6 +387,7 @@ struct Config
MemoryReclaimMode MemoryReclaim = MemoryReclaimMode::DropCache;
bool EnableSparseVhd = false;
UINT64 VhdSizeBytes = 0x10000000000; // 1TB
VhdType VhdDefaultType = VhdType::Dynamic;

wsl::shared::string::MacAddress MacAddress;
std::wstring NatIpAddress;
Expand Down
8 changes: 8 additions & 0 deletions src/windows/inc/WslCoreConfigInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ enum WslConfigEntry
SwapSizeBytes,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wslsettings.exe doesn't actually display this setting, so let's remove the changes in libwsl and wslsettings

SwapFilePath,
VhdSizeBytes,
VhdType,
Networking,
FirewallEnabled,
IgnoredPorts,
Expand Down Expand Up @@ -65,6 +66,12 @@ enum MemoryReclaimConfiguration
DropCache = 2
};

enum VhdTypeConfiguration
{
Dynamic = 0,
Fixed = 1
};

typedef struct WslConfig* WslConfig_t;

struct WslConfigSetting
Expand All @@ -78,6 +85,7 @@ struct WslConfigSetting
bool BoolValue;
enum NetworkingConfiguration NetworkingConfigurationValue;
enum MemoryReclaimConfiguration MemoryReclaimModeValue;
enum VhdTypeConfiguration VhdTypeValue;
};
};

Expand Down
15 changes: 15 additions & 0 deletions src/windows/libwsl/WslCoreConfigInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ WslConfigSetting GetWslConfigSetting(WslConfig_t wslConfig, WslConfigEntry wslCo
static_assert(std::is_same<decltype(wslConfigSetting.UInt64Value), decltype(wslConfig->Config.VhdSizeBytes)>::value);
wslConfigSetting.UInt64Value = wslConfig->Config.VhdSizeBytes;
break;
case VhdType:
wslConfigSetting.VhdTypeValue = static_cast<VhdTypeConfiguration>(wslConfig->Config.VhdDefaultType);
break;
case Networking:
wslConfigSetting.NetworkingConfigurationValue = static_cast<NetworkingConfiguration>(wslConfig->Config.NetworkingMode);
break;
Expand Down Expand Up @@ -325,6 +328,18 @@ unsigned long SetWslConfigSetting(WslConfig_t wslConfig, WslConfigSetting wslCon
MemoryString(defaultConfig.VhdSizeBytes),
MemoryString(wslConfigSetting.UInt64Value),
wslConfig->Config.VhdSizeBytes);
case VhdType:
{
wsl::core::VhdType vhdTypeConfiguration{static_cast<wsl::core::VhdType>(wslConfigSetting.VhdTypeValue)};
ConfigKey key(ConfigSetting::DefaultVhdType, wsl::core::VhdTypes, vhdTypeConfiguration);
const auto removeKey = defaultConfig.VhdDefaultType == vhdTypeConfiguration;
const auto result = wslConfig->Config.WriteConfigFile(wslConfig->ConfigFilePath.c_str(), key, removeKey);
if (result == 0)
{
wslConfig->Config.VhdDefaultType = vhdTypeConfiguration;
}
return result;
}
case Networking:
{
wsl::core::NetworkingMode networkingConfiguration{static_cast<wsl::core::NetworkingMode>(wslConfigSetting.NetworkingConfigurationValue)};
Expand Down
9 changes: 6 additions & 3 deletions src/windows/service/exe/LxssUserSession.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1407,8 +1407,7 @@ HRESULT LxssUserSessionImpl::RegisterDistribution(
RETURN_HR_IF(E_INVALIDARG, WI_IsFlagSet(Flags, LXSS_IMPORT_DISTRO_FLAGS_FIXED_VHD));
}

// Registering a distro with a fixed VHD is only allowed if a size is specified.
RETURN_HR_IF(E_INVALIDARG, VhdSize == 0 && WI_IsFlagSet(Flags, LXSS_IMPORT_DISTRO_FLAGS_FIXED_VHD));
// Note: Validation for fixed VHD without explicit size is now allowed - defaults from .wslconfig will be applied below.

// Registering a WSL1 distro is not possible if the lxcore driver is not present.
RETURN_HR_IF(WSL_E_WSL1_NOT_SUPPORTED, (Version == LXSS_WSL_VERSION_1) && !g_lxcoreInitialized);
Expand Down Expand Up @@ -1508,8 +1507,12 @@ HRESULT LxssUserSessionImpl::RegisterDistribution(
VhdSize = config.VhdSizeBytes;
}

// Determine VHD type: use explicit flag if present, otherwise use config default
bool useFixedVhd = WI_IsFlagSet(Flags, LXSS_IMPORT_DISTRO_FLAGS_FIXED_VHD) ||
(config.VhdDefaultType == wsl::core::VhdType::Fixed);

wsl::core::filesystem::CreateVhd(
configuration.VhdFilePath.c_str(), VhdSize, GetUserSid(), config.EnableSparseVhd, WI_IsFlagSet(Flags, LXSS_IMPORT_DISTRO_FLAGS_FIXED_VHD));
configuration.VhdFilePath.c_str(), VhdSize, GetUserSid(), config.EnableSparseVhd, useFixedVhd);

deleteFlags = LXSS_DELETE_DISTRO_FLAGS_VHD;
}
Expand Down
49 changes: 28 additions & 21 deletions src/windows/wslsettings/LibWsl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,27 +23,28 @@ public enum WslConfigEntry
SwapSizeBytes = 3,
SwapFilePath = 4,
VhdSizeBytes = 5,
NetworkingMode = 6,
FirewallEnabled = 7,
IgnoredPorts = 8,
LocalhostForwardingEnabled = 9,
HostAddressLoopbackEnabled = 10,
AutoProxyEnabled = 11,
InitialAutoProxyTimeout = 12,
DNSProxyEnabled = 13,
DNSTunnelingEnabled = 14,
BestEffortDNSParsingEnabled = 15,
AutoMemoryReclaim = 16,
GUIApplicationsEnabled = 17,
NestedVirtualizationEnabled = 18,
SafeModeEnabled = 19,
SparseVHDEnabled = 20,
VMIdleTimeout = 21,
DebugConsoleEnabled = 22,
HardwarePerformanceCountersEnabled = 23,
KernelPath = 24,
SystemDistroPath = 25,
KernelModulesPath = 26
VhdType = 6,
NetworkingMode = 7,
FirewallEnabled = 8,
IgnoredPorts = 9,
LocalhostForwardingEnabled = 10,
HostAddressLoopbackEnabled = 11,
AutoProxyEnabled = 12,
InitialAutoProxyTimeout = 13,
DNSProxyEnabled = 14,
DNSTunnelingEnabled = 15,
BestEffortDNSParsingEnabled = 16,
AutoMemoryReclaim = 17,
GUIApplicationsEnabled = 18,
NestedVirtualizationEnabled = 19,
SafeModeEnabled = 20,
SparseVHDEnabled = 21,
VMIdleTimeout = 22,
DebugConsoleEnabled = 23,
HardwarePerformanceCountersEnabled = 24,
KernelPath = 25,
SystemDistroPath = 26,
KernelModulesPath = 27
}

public enum NetworkingConfiguration
Expand All @@ -62,6 +63,12 @@ public enum MemoryReclaimMode
DropCache = 2
}

public enum VhdType
{
Dynamic = 0,
Fixed = 1
}

public unsafe partial class WslConfig
{
public partial struct __Internal
Expand Down
66 changes: 66 additions & 0 deletions test/windows/UnitTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,72 @@ class UnitTests
}
}

TEST_METHOD(DefaultVhdTypeConfiguration)
{
WSL2_TEST_ONLY();

// Test that defaultVhdType setting in .wslconfig works correctly
const auto testDistroName = L"TestDefaultVhdType";
const auto configContent = L"[wsl2]\ndefaultVhdSize=10GB\ndefaultVhdType=fixed\n";

WslConfigChange config(configContent);

// Clean up any existing test distro
LxsstuLaunchWsl(std::format(L"--unregister {}", testDistroName));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use a different name for the distribution we use for this test so we don't have to unregister the main one


auto cleanup = wil::scope_exit([&] {
LxsstuLaunchWsl(std::format(L"--unregister {}", testDistroName));
});

// Install a distribution using --fixed-vhd without --vhd-size
// This should use the defaultVhdSize from config
auto [out, err] = LxsstuLaunchWslAndCaptureOutput(
std::format(L"--install Ubuntu-24.04 --name {} --no-launch --fixed-vhd", testDistroName));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should avoid to depend on networking in the tests, since that can create unstable test results.

Instead of downloading ubuntu, let' use the test distro tar. Something like this should do:

std::format(L"--install --from-file \"{}\" --no-launch --name test_vhd_flag --fixed-vhd", g_testDistroPath));


// Verify installation succeeded
VERIFY_ARE_NOT_EQUAL(out.find(L"completed successfully"), std::wstring::npos);

// Get the VHD path for the test distribution
auto distroList = LxsstuEnumerateDistributions();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: it might be worth extracting this logic into a lambda. Something like:

auto validateVhdType = [](const char* Expected){...};

So the test can just do
validateVhdType("Fixed");

auto distroIt = std::find_if(distroList.begin(), distroList.end(),
[&](const auto& d) { return d.Name == testDistroName; });

if (distroIt != distroList.end())
{
auto vhdPath = distroIt->BasePath / L"ext4.vhdx";

// Verify the VHD type is Fixed as specified in config
auto [vhdType, _] = LxsstuLaunchPowershellAndCaptureOutput(
std::format(L"(Get-VHD '{}').VhdType", vhdPath.wstring()));
VERIFY_ARE_EQUAL(vhdType, L"Fixed\r\n");
}

// Test with defaultVhdType=dynamic (default)
config.Update(L"[wsl2]\ndefaultVhdSize=10GB\ndefaultVhdType=dynamic\n");

LxsstuLaunchWsl(std::format(L"--unregister {}", testDistroName));

// Install without --fixed-vhd, should use dynamic from config
auto [out2, err2] = LxsstuLaunchWslAndCaptureOutput(
std::format(L"--install Ubuntu-24.04 --name {} --no-launch", testDistroName));

VERIFY_ARE_NOT_EQUAL(out2.find(L"completed successfully"), std::wstring::npos);

distroList = LxsstuEnumerateDistributions();
distroIt = std::find_if(distroList.begin(), distroList.end(),
[&](const auto& d) { return d.Name == testDistroName; });

if (distroIt != distroList.end())
{
auto vhdPath = distroIt->BasePath / L"ext4.vhdx";

// Verify the VHD type is Dynamic
auto [vhdType, _] = LxsstuLaunchPowershellAndCaptureOutput(
std::format(L"(Get-VHD '{}').VhdType", vhdPath.wstring()));
VERIFY_ARE_EQUAL(vhdType, L"Dynamic\r\n");
}
}

TEST_METHOD(SystemdSafeMode)
{
WSL2_TEST_ONLY();
Expand Down