Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
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: 5 additions & 1 deletion localization/strings/en-US/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,9 @@ Arguments for managing Windows Subsystem for Linux:
--resize <MemoryString>
Resize the disk of the distribution to the specified size.
Comment thread
Guayamose marked this conversation as resolved.

Comment thread
Guayamose marked this conversation as resolved.
Comment thread
Guayamose marked this conversation as resolved.
--compact
Compact the VHDX file of a stopped WSL 2 distribution.

Comment thread
Guayamose marked this conversation as resolved.
--mount <Disk>
Attaches and mounts a physical or virtual disk in all WSL 2 distributions.

Expand Down Expand Up @@ -611,7 +614,8 @@ 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="--compact
"}{Locked="--mount "}{Locked="--vhd
"}{Locked="--bare
"}{Locked="--name "}{Locked="--type "}{Locked="--options "}{Locked="--partition "}{Locked="--set-default-version "}{Locked="--shutdown
"}{Locked="--force
Expand Down
15 changes: 13 additions & 2 deletions src/windows/common/WslClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -765,6 +765,10 @@ int ListDistributionsHelper(_In_ ListOptions options)
state = L"Exporting";
break;

case LxssDistributionStateCompacting:
state = L"Compacting";
break;

default:
break;
}
Expand All @@ -790,7 +794,8 @@ int ListDistributionsHelper(_In_ ListOptions options)
std::erase_if(distros, [&](const auto& entry) {
return (
(entry.State == LxssDistributionStateInstalling) || (entry.State == LxssDistributionStateUninstalling) ||
(entry.State == LxssDistributionStateConverting) || (entry.State == LxssDistributionStateExporting));
(entry.State == LxssDistributionStateConverting) || (entry.State == LxssDistributionStateExporting) ||
(entry.State == LxssDistributionStateCompacting));
});
}

Expand Down Expand Up @@ -887,6 +892,7 @@ int Manage(_In_ std::wstring_view commandLine)
std::optional<std::wstring> move;
std::optional<std::wstring> defaultUser;
std::optional<uint64_t> resize;
bool compact = false;
bool allowUnsafe = false;

ArgumentParser parser(std::wstring{commandLine}, WSL_BINARY_NAME, 0);
Expand All @@ -895,6 +901,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(compact, WSL_MANAGE_ARG_COMPACT_OPTION_LONG);
parser.AddArgument(allowUnsafe, WSL_MANAGE_ARG_ALLOW_UNSAFE);
parser.Parse();

Expand All @@ -903,7 +910,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() + compact != 1)
{
THROW_HR(WSL_E_INVALID_USAGE);
}
Comment thread
Guayamose marked this conversation as resolved.
Comment thread
Guayamose marked this conversation as resolved.
Expand Down Expand Up @@ -950,6 +957,10 @@ int Manage(_In_ std::wstring_view commandLine)
{
THROW_IF_FAILED(service.ResizeDistribution(&distroGuid, resize.value()));
}
else if (compact)
{
THROW_IF_FAILED(service.CompactDistribution(&distroGuid));
}

wsl::windows::common::wslutil::PrintSystemError(ERROR_SUCCESS);
return 0;
Expand Down
10 changes: 10 additions & 0 deletions src/windows/common/WslCoreFilesystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,16 @@ wil::unique_handle wsl::core::filesystem::OpenVhd(_In_ LPCWSTR Path, _In_ VIRTUA
return disk;
}

void wsl::core::filesystem::CompactVhd(_In_ LPCWSTR Path)
{
auto diskHandle = OpenVhd(Path, VIRTUAL_DISK_ACCESS_GET_INFO | VIRTUAL_DISK_ACCESS_METAOPS);

COMPACT_VIRTUAL_DISK_PARAMETERS compact{};
compact.Version = COMPACT_VIRTUAL_DISK_VERSION_1;

THROW_IF_WIN32_ERROR(CompactVirtualDisk(diskHandle.get(), COMPACT_VIRTUAL_DISK_FLAG_NONE, &compact, nullptr));
}

void wsl::core::filesystem::ResizeExistingVhd(_In_ HANDLE diskHandle, _In_ ULONGLONG maximumSize, _In_ RESIZE_VIRTUAL_DISK_FLAG resizeFlag)
{
RESIZE_VIRTUAL_DISK_PARAMETERS resize{};
Expand Down
2 changes: 2 additions & 0 deletions src/windows/common/WslCoreFilesystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ void CreateVhd(_In_ LPCWSTR target, _In_ ULONGLONG maximumSize, _In_ PSID userSi

wil::unique_handle OpenVhd(_In_ LPCWSTR Path, _In_ VIRTUAL_DISK_ACCESS_MASK Mask);

void CompactVhd(_In_ LPCWSTR Path);

void ResizeExistingVhd(_In_ HANDLE diskHandle, _In_ ULONGLONG maximumSize, _In_ RESIZE_VIRTUAL_DISK_FLAG resizeFlag);

ULONGLONG GetDiskSize(_In_ HANDLE diskHandle);
Expand Down
7 changes: 7 additions & 0 deletions src/windows/common/svccomm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -652,6 +652,13 @@ wsl::windows::common::SvcComm::ResizeDistribution(_In_ LPCGUID DistroGuid, _In_
RETURN_HR(result);
}

HRESULT
wsl::windows::common::SvcComm::CompactDistribution(_In_ LPCGUID DistroGuid) const
{
ClientExecutionContext context;
RETURN_HR(m_userSession->CompactDistribution(DistroGuid, context.OutError()));
}

HRESULT
wsl::windows::common::SvcComm::SetVersion(_In_ LPCGUID DistroGuid, _In_ ULONG Version) const
{
Expand Down
3 changes: 3 additions & 0 deletions src/windows/common/svccomm.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ class SvcComm
HRESULT
ResizeDistribution(_In_ LPCGUID DistroGuid, _In_ ULONG64 NewSize) const;

HRESULT
CompactDistribution(_In_ LPCGUID DistroGuid) const;

void SetDefaultDistribution(_In_ LPCGUID DistroGuid) const;

HRESULT
Expand Down
1 change: 1 addition & 0 deletions src/windows/inc/wsl.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,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_COMPACT_OPTION_LONG L"--compact"
#define WSL_MOUNT_ARG L"--mount"
#define WSL_MOUNT_ARG_VHD_OPTION_LONG L"--vhd"
#define WSL_MOUNT_ARG_BARE_OPTION_LONG L"--bare"
Expand Down
51 changes: 49 additions & 2 deletions src/windows/service/exe/LxssUserSession.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,18 @@ try
}
CATCH_RETURN()

HRESULT STDMETHODCALLTYPE LxssUserSession::CompactDistribution(_In_ LPCGUID DistroGuid, _Out_ LXSS_ERROR_INFO* Error)
try
{
ServiceExecutionContext context(Error);

const auto session = m_session.lock();
RETURN_HR_IF(RPC_E_DISCONNECTED, !session);

return session->CompactDistribution(DistroGuid);
}
CATCH_RETURN()

HRESULT STDMETHODCALLTYPE LxssUserSession::SetVersion(_In_ LPCGUID DistroGuid, _In_ ULONG Version, _In_ HANDLE StdErrHandle, _Out_ LXSS_ERROR_INFO* Error)
try
{
Expand Down Expand Up @@ -913,6 +925,7 @@ HRESULT LxssUserSessionImpl::MoveDistribution(_In_ LPCGUID DistroGuid, _In_ LPCW

// Fail if the distribution is running.
RETURN_HR_IF(WSL_E_DISTRO_NOT_STOPPED, m_runningInstances.contains(*DistroGuid));
_EnsureNotLocked(DistroGuid);

// Lookup the distribution configuration
const auto lxssKey = s_OpenLxssUserKey();
Expand Down Expand Up @@ -1759,6 +1772,8 @@ try
THROW_HR_WITH_USER_ERROR(E_INVALIDARG, wsl::shared::Localization::MessageSparseVhdDisabled());
}

_EnsureNotLocked(DistroGuid);

// Don't attempt if running
RETURN_HR_IF(WSL_E_DISTRO_NOT_STOPPED, m_runningInstances.contains(*DistroGuid));

Expand Down Expand Up @@ -1790,6 +1805,7 @@ try
const auto registration = DistributionRegistration::Open(lxssKey.get(), *DistroGuid);
const auto configuration = s_GetDistributionConfiguration(registration);
RETURN_HR_IF(WSL_E_WSL2_NEEDED, WI_IsFlagClear(configuration.Flags, LXSS_DISTRO_FLAGS_VM_MODE));
_EnsureNotLocked(DistroGuid);

const auto& vhdPath = configuration.VhdFilePath;
if (m_utilityVm && m_utilityVm->IsVhdAttached(vhdPath.c_str()))
Expand Down Expand Up @@ -1837,6 +1853,37 @@ try
}
CATCH_RETURN()

HRESULT LxssUserSessionImpl::CompactDistribution(_In_ LPCGUID DistroGuid)
try
{
auto runAsUser = wil::CoImpersonateClient();
std::filesystem::path vhdPath;
LXSS_DISTRO_CONFIGURATION configuration;

{
std::lock_guard lock(m_instanceLock);
const wil::unique_hkey lxssKey = s_OpenLxssUserKey();
const auto registration = DistributionRegistration::Open(lxssKey.get(), *DistroGuid);
configuration = s_GetDistributionConfiguration(registration);
RETURN_HR_IF(WSL_E_WSL2_NEEDED, WI_IsFlagClear(configuration.Flags, LXSS_DISTRO_FLAGS_VM_MODE));

vhdPath = configuration.VhdFilePath;
Comment thread
Guayamose marked this conversation as resolved.
_ConversionBegin(configuration.DistroId, LxssDistributionStateCompacting);
}

Comment thread
Guayamose marked this conversation as resolved.
auto compactionComplete = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [&] { _ConversionComplete(configuration.DistroId); });

const auto result = wil::ResultFromException([&] { wsl::core::filesystem::CompactVhd(vhdPath.c_str()); });
if (result == HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION))
{
THROW_HR_WITH_USER_ERROR(result, wsl::shared::Localization::MessageVhdInUse());
}

THROW_IF_FAILED(result);
return S_OK;
}
CATCH_RETURN()

HRESULT LxssUserSessionImpl::SetVersion(_In_ LPCGUID DistroGuid, _In_ ULONG Version, _In_ HANDLE StderrHandle)
{
RETURN_HR_IF(E_INVALIDARG, ((Version != LXSS_WSL_VERSION_1) && (Version != LXSS_WSL_VERSION_2)));
Expand Down Expand Up @@ -3108,13 +3155,13 @@ std::vector<DistributionRegistration> LxssUserSessionImpl::_EnumerateDistributio
_Requires_lock_held_(m_instanceLock)
void LxssUserSessionImpl::_EnsureNotLocked(_In_ LPCGUID DistroGuid, const std::source_location& location)
{
const auto found = std::find_if(m_lockedDistributions.begin(), m_lockedDistributions.end(), [&DistroGuid](const auto& entry) {
const auto locked = std::find_if(m_lockedDistributions.begin(), m_lockedDistributions.end(), [&DistroGuid](const auto& entry) {
return IsEqualGUID(entry.first, *DistroGuid);
});

THROW_HR_IF_MSG(
E_ILLEGAL_STATE_CHANGE,
(found != m_lockedDistributions.end()),
locked != m_lockedDistributions.end(),
"%hs, %hs:%u",
location.function_name(),
location.file_name(),
Expand Down
11 changes: 11 additions & 0 deletions src/windows/service/exe/LxssUserSession.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,11 @@ class DECLSPEC_UUID("a9b7a1b9-0671-405c-95f1-e0612cb4ce7e") LxssUserSession
/// </summary>
IFACEMETHOD(ResizeDistribution)(_In_ LPCGUID DistroGuid, _In_ HANDLE OutputHandle, _In_ ULONG64 NewSize, _Out_ LXSS_ERROR_INFO* Error) override;

/// <summary>
/// Compacts the virtual disk of a distribution.
/// </summary>
IFACEMETHOD(CompactDistribution)(_In_ LPCGUID DistroGuid, _Out_ LXSS_ERROR_INFO* Error) override;

/// <summary>
/// Sets the default distribution.
/// </summary>
Expand Down Expand Up @@ -467,6 +472,12 @@ class LxssUserSessionImpl
HRESULT
ResizeDistribution(_In_ LPCGUID DistroGuid, _In_ HANDLE OutputHandle, _In_ ULONG64 NewSize);

/// <summary>
/// Compacts the disk of a distribution.
/// </summary>
HRESULT
CompactDistribution(_In_ LPCGUID DistroGuid);

/// <summary>
/// Sets the default distribution.
/// </summary>
Expand Down
7 changes: 6 additions & 1 deletion src/windows/service/inc/wslservice.idl
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ typedef enum _LxssDistributionState
LxssDistributionStateInstalling,
LxssDistributionStateUninstalling,
LxssDistributionStateConverting,
LxssDistributionStateExporting
LxssDistributionStateExporting,
LxssDistributionStateCompacting
} LxssDistributionState;

typedef
Expand Down Expand Up @@ -344,6 +345,10 @@ interface ILxssUserSession : IUnknown
[in] LPCGUID DistroGuid,
[in] LPCWSTR DistributionName,
[ in, out ] LXSS_ERROR_INFO * Error);

Comment thread
Guayamose marked this conversation as resolved.
Comment thread
Guayamose marked this conversation as resolved.
Comment thread
Guayamose marked this conversation as resolved.
HRESULT CompactDistribution(
[in] LPCGUID DistroGuid,
[in, out] LXSS_ERROR_INFO* Error);
};


Expand Down
Loading