I know this is a few years old, so you may not have this particular need any longer. However, in the latest WSL releases, the default maximum size of the dynamic VHDX has been increased to 1TB, so the problem may be even worse.
I need a solution that ideally doesn't require manual steps, but at the very least doesn't require me to shutdown WSL
While this solution has a lot of manual steps and a shutdown, it's one-time configuration work to set things up. For there, you can simply use one wsl --import-in-place
command to start up new WSL instances using the smaller drive size on the build server.
Also, don't be too scared by the length of the steps/post below - I'm just very (perhaps overly) detailed.
This particular solution requires Windows 11 or Windows 10 running UBR 2311 or later (see this answer for details on how to update currently).
To summarize what I propose:
- Create a new VHD with your desired maximum size
- Mount it in WSL and create the filesystem.
- Copy over all files from an existing WSL distro to the new VHD.
wsl --import
the VHD as a new distribution.
Full details:
If you are on a Windows 10 xxxxx.2311 or Windows 11 22H2 release:
Run wsl --update
, which should update your WSL to use the new application package (Store) version of WSL. If you do not have access to the Store from your build server, see the later half of this answer for manual installation steps.
You'll need two distributions installed. The one you want to copy and one for doing the copying (a "temp" distro if needed). If you are working with Ubuntu, for instance, then you can just create a new Ubuntu-22.04 instance from the Store.
In an admin PowerShell, create a new dynamic VHD using:
new-vhd -Dynamic -SizeBytes 30gb -BlockSizeBytes 1mb -path ./ext4.vhdx
The -BlockSizeBytes
matches the existing setting for WSL2 ext4.vhdx
files.
Exit the Admin PowerShell and in a new, regular-user PowerShell, run:
Get-ChildItem HKCU:\Software\Microsoft\Windows\CurrentVersion\Lxss\ |
ForEach-Object {
(Get-ItemProperty $_.PSPATH) | Select-Object DistributionName,BasePath
}
Make note of the path of the original distribution that you want to copy. We'll call this <srcdrive>
.
wsl --shutdown
to make sure no files in the original distribution are in use. Make sure there's no process that might automatically restart that distribution (e.g. Docker Desktop).
Start the "temp" distribution that you will be using to do the copying with wsl ~ -d <distroname>
lsblk
and take note of the existing devices listed. Make sure to identify any devices that are the same size as the one you'll be formatting. You don't want to overwrite one that is already in use!
Exit WSL and return to PowerShell.
wsl --mount --vhd --bare \path\to\the\new\ext4.vhdx
wsl --mount --vhd --name srcdrive path\to\<srcdrive.vhdx>
Using the path you determined above for <srcdrive>
.
Start your temp WSL instance again.
lsblk
Confirm the device name that you want to format. It should be the only 30G device there, hopefully. Regardless, it should be the only 30G device in the list that wasn't there when we checked before the --mount
. We'll call this newdev
:
sudo mkfs.ext4 /dev/<newdev>
sudo mount -t ext4 /dev/<newdev> /mnt/wsl/newdrive -o X-mount.mkdir
You should have two mounts:
/mnt/wsl/srcdrive
/mnt/wsl/newdrive
srcdrive
should look like the filesystem from your existing distribution that you want to copy. newdrive
should currently be empty other than the default lost+found
.
Copy over the filesystem:
sudo cp -axT /mnt/wsl/srcdrive/ /mnt/wsl/newdrive/
Exit the WSL temp distribution
Back in PowerShell:
wsl --shutdown
wsl --import-in-place <new_distro_name> \path\to\the\new\ext4.vhdx
Finally, start the new distro with wsl ~ -d <new_distro_name>
. It will start as the root user. To set your default user, create a /etc/wsl.conf
file as noted in this answer.
You can now use the new VHD to seed your build system with multiple (if needed) smaller WSL distributions with just an additional wsl --import-in-place
.