microsoft / WSL

Issues found on WSL
https://docs.microsoft.com/windows/wsl
MIT License
17.42k stars 824 forks source link

WSL 2 should automatically release disk space back to the host OS #4699

Open dsmaher opened 4 years ago

dsmaher commented 4 years ago

Is your feature request related to a problem? Please describe. I occasionally have workloads that consume large amounts of disk space for temporary use in /tmp. For example, transcoding large video files or processing large datasets exported from a database. Since WSL2 stores its filesystem on a .vhdx, that file grows when the dataset is processed and never releases that space. Also, it doesn't appear to re-use released disk space in the .vhdx when files are deleted... it seems to prefer to grow the file rather than re-use existing empty space. (I haven't explicitly tested that theory, but my workload deletes temporary files as they are used and I never had enough of them existing simultaneously to reach 250GB, but the size of the .vhdx eventually expanded to that size.

When I'm done with that workload, I have to:

wsl --shutdown
optimize-vhd -Path .\ext4.vhdx -Mode full

This is annoying since it basically means that my system backups include a huge .vhdx file that is mostly empty. Also, until about 2 weeks ago, it was consuming the entire remainder of my system disk. I had only 50GB free, which was enough to handle the workload, but since it continued to grow even after files were removed, that didn't matter. (I figured it was time to upgrade the disk size anyway)

Describe the solution you'd like Automatic compaction of the .vhdx, or a way to do so while WSL2 is still running so that I can schedule it for frequent cleanups.

Describe alternatives you've considered

caner-cetin commented 1 year ago

Absolutely agreeing with jerivas, we have came to a point that "just buy an ssd".

okibcn commented 1 year ago

you shouldn't use Docker with WSL at this stage, just go with another route. Docker Desktop is way too slow and way too bloated, and CLI Docker without Docker Desktop is eating your space until there is nothing left.

@canercetin-randomguy The best way to work with docker is to completely bypass docker desktop. My VHDL image for docker containers is about 1500 MB. The /var/lib/docker folder (especially the huge /var/lib/docker/overlay2 folder) is in a qcow2 image in a folder outside the vhdx, in /mnt/c/whatever_you_like. This way, container activity doesn't add any garbage to vhdx files. qcow2 format is way better at managing an ext4 filesystem inside.

Other than that, it is a good practice to prune your unused containers and keep some kind of hygiene in the docker folder.

@jerivas I understand your frustration, but if they lock this thread, it would be like accepting that the solution is to get a bigger drive. That is the current first-place solution in the Docker Desktop documentation:

image

So, just because we have come to a point that "just buy an SSD" seems the only way forward, is the reason why this thread shouldn't be locked.

The real problem here is not in WSL, it is actually the inability of Hyper-V to properly manage space in non-NTFS partitions inside VHDX images. WSL team had no other choice but to use VHDX (from Microsoft) to virtualize the storage hardware, so probably this issue should be elevated to another team able to evolve the VHDX management system....

...KNOCK, KNOCK... MICROSOFT, ARE YOU THERE??????

lucasbasquerotto commented 1 year ago

Can someone at Microsoft please lock this issue until an official response is ready to be shared? The conversation has been completely derailed 😞

https://github.com/microsoft/WSL/issues/4699#issuecomment-1433530372

The problem is that a locked issue can't even receive πŸ‘, which may end up making this issue and comments seem to be less important / with less interest than it actually is (although it already has more than 680 πŸ‘, so this issue is already considered very important by the community).

In any case, it's possible to customize the subscription (right above the button) to make it notify only when this issue is closed, to avoid undesired comments.

DanielHabenicht commented 1 year ago

This is really hurting me on running scientific workload in docker I've been running batch jobs on my machine and only remove containers on a scheduled command and still my system is running out of space... bringing me to this issue https://github.com/docker/for-win/issues/244 which is linked to this issue as a base problem.

okibcn commented 1 year ago

This is really hurting me on running scientific workload in docker I've been running batch jobs on my machine and only remove containers on a scheduled command and still my system is running out of space... bringing me to this issue docker/for-win#244 which is linked to this issue as a base problem.

@DanielHabenicht I am using docker for development, with a lot of scripts creating and pruning containers and images. I use wslcompact after I finish each work and delete all the garbage in the docker image. That ensures my WSL docker image is always small.

I have improved my WSL docker image. It is now a 311 MB VHDX, 7zipped down to 48MB. I use these 3 supporting functions in powershell $PROFILE to use docker from PowerShell:

function docker { wsl -d alpine-docker docker $args }

I also have this other function in my PowerShell profile to prune everything leaving the image clean.

function dockerclean { 
    docker stop $(docker ps -a -q) -t 0
    docker container ls -a
    docker image ls -a
    docker system prune -a 
}

And this one to know the actual size used by docker images and containers

function dockersize { wsl -d docker du -hd 1 /var/lib/docker/ }

Then, when I work with containers, I do:

  1. start WSL docker image from PowerShell (note > prompt for PowerShell commands, and $ for shell commands):

    > wsl -d alpine-docker
    $ dockerd &
    $ exit
  2. All my docker work here.....

  3. Then after working:

    > dockerclean
    > wslcompact -c -y alpine-docker

    That returns my alpine-docker VHDX from tens of GBs back to 311 MB. Always.

qwertynik commented 1 year ago

Windows should atleast collaborate with @okibcn and recommend a solution🀝 WSL2 was one of the reasons for not switching back to Mac OS, but issues like these make WSL2 less attractive.

talves commented 1 year ago

For anyone who's using WSL2 and need to make their disk larger than the old 250G size. I cleaned up my drive and used: https://github.com/microsoft/WSL/issues/4699#issuecomment-627133168 to get back the space.

After restoring to my minimum size, I used these docs to make the maximum disk larger: https://learn.microsoft.com/en-us/windows/wsl/disk-space

okibcn commented 1 year ago

For anyone who's using WSL2 and need to make their disk larger than the old 250G size. I cleaned up my drive and used: #4699 (comment) to get back the space.

After restoring to my minimum size, I used these docs to make the maximum disk larger: https://learn.microsoft.com/en-us/windows/wsl/disk-space

wslcompact also updates the drive capacity to 1 TB while reducing the size of the VHDX file in three easy steps:

  1. install wslcompact
  2. ensure resize2fs is installed in your distro
  3. run this from powershell replacing DISTRO with the name of the distro you want to expand,
    wslcompact -c -y DISTRO
    wsl --shutdown
    wsl -d DISTRO resize2fs /dev/sdc

    You will have a compacted VHDX file with a whole 1TB in your ext4 filesystem.

OrangeDog commented 1 year ago

I couldn't get the optimize-vhd command to work, but using the Hyper-V Manager GUI had no problems.

zba commented 1 year ago

may be there is way to complete stop using this vhdx images for docker images ? any way to mount just directory ? I found that manage disk space with this really disturbing.

zachNA2 commented 1 year ago

Will just add its 2023, and still no integrated way to receive all my space back. I just ran df -h after running compact vhd I get this

Filesystem      Size  Used Avail Use% Mounted on`
/dev/sdc       1007G  211G  745G  23% /`

Why do you not make a tool which prevents making the whole experience an adrenaline rush for if my data will be corrupt afterwards... Feel like we're all asking for something that's very reasonable to achieve in the last 4 YEARS.

ak2 commented 1 year ago

I tried to use Resize-VHD to reduce the maximum size of a freshly installed distro from the default 1TB, but I just get the following error:

> Resize-VHD -path ext4.vhdx -SizeBytes 128GB […]AppData\Local\Packages\CanonicalGroupLimited.Ubuntu22.04LTS_79rhkp1fndgsc\LocalState\ext4.vhdx': The requested operation could not be completed because the virtual disk's minimum safe size could not be determined. This may be due to a missing or corrupt partition table. (0xC03A0026).

Anyone got an idea what might be going wrong there?

Or is there another way to reduce the maximum size?

ak2 commented 1 year ago

Wslcompact looks like a great tool for shrinking an image that has already got out of hand, but I'd like to reduce the 1TB default limit on the VHDX size while the image is still small, to prevent it from eating up too much of a 512GB SSD.

m1o1 commented 1 year ago

There's a lot of comments on this issue already but if it hasn't been mentioned yet, I partitioned my disk and made a 256GB partition exclusively for WSL, and so far haven't had any issues with that.

piradata commented 1 year ago

There is like, 120Gb of usave in VHDX, and when I compact it goes to 40Gb...

My entire SSD as 256Gb in total, so wsl is eating half of that for no good reason :(

Chiramisu commented 1 year ago

There's a lot of comments on this issue already but if it hasn't been mentioned yet, I partitioned my disk and made a 256GB partition exclusively for WSL, and so far haven't had any issues with that.

Interesting. I didn't know you could install WSL to a dedicated partition. Is there an official guide on that?

mmarinchenko commented 1 year ago

@Chiramisu

Interesting. I didn't know you could install WSL to a dedicated partition. Is there an official guide on that?

As far as I know, this is not possible, i.e. the WSL itself cannot be installed on a separate partition.

But for WSL2 distros you can move disk image files to a custom folder using --export/--import. See https://github.com/docker/for-win/issues/13408#issuecomment-1523397767 for detailed example (replace docker-desktop-data with your distro).

If you're using Docker Desktop you can also try a different approach. See another https://github.com/docker/for-win/issues/13408#issuecomment-1642506519.

igortas commented 1 year ago

Nor wsl-compact nor optmize-vhd works properly. optimize-vhd not cleaning the extra space at all, wsl-compact clean the space a bit, once (still my instance is near 50gb with one dumb project installed and nothing else).

craigloewen-msft commented 1 year ago

Hi folks, we have just put out a new experimental feature in WSL that aims to address this in the latest update. You can now run wsl --manage <distroName> --set-sparse true to set it to a sparse VHD that will automatically reclaim memory. This will allow it to shrink in size as you use it!

More info on this release and the changes can be found here in the blog post. Please tell us what you think!

dgw commented 1 year ago

You can now run wsl --manage <distroName> --set-sparse true to set it to a sparse VHD that will automatically reclaim memory. This will allow it to shrink in size as you use it!

Makes sense that this is experimental at first, but if no issues arise, will sparse VHDs become the default in a future WSL update?

nickjj commented 1 year ago

@craigloewen-msft Nice! Do we need to worry about or think about SSD wear and tear when sparse is enabled?

RandomDSdevel commented 1 year ago

Hi folks, we have just put out a new experimental feature in WSL that aims to address this in the latest update. You can now run wsl --manage <distroName> --set-sparse true to set it to a sparse VHD that will automatically reclaim memory. This will allow it to shrink in size as you use it!

More info on this release and the changes can be found here in the blog post. Please tell us what you think!

     Awesome! Does this work with WSL 2 instance whose VHD images have had NTGS compression applied to them on the Windows side, too?

daniel5gh commented 1 year ago

@craigloewen-msft Nice!

I ran wsl --manage ubuntu --set-sparse true and purged docker data as you showed in the demo video. Docker Desktop's ext4.vhdx did not shrink.

Since I have an existing docker-desktop-data distro, as managed by docker desktop, would I also need to wsl --manage docker-desktop-data --set-sparse true? Makes sense I would need that, but I did not see any explicit instructions for this case and since this is experimental I don't just want to yolo it.

craigloewen-msft commented 1 year ago

Yes to clarify you would need to run it for your given distro. So @daniel5gh please run wsl --manage docker-desktop-data --set-sparse true and you should see it now shrink in size automatically. (Doing it for Ubuntu only affects your Ubuntu distro :) )

daniel5gh commented 1 year ago

Yes to clarify you would need to run it for your given distro. So @daniel5gh please run wsl --manage docker-desktop-data --set-sparse true and you should see it now shrink in size automatically. (Doing it for Ubuntu only affects your Ubuntu distro :) )

Awesome, thanks for the clarification! But, it doesn't seem to work in my case.

I first enabled sparse on docker-desktop-data which appeared to not do anything with the vhdx's size, at least not after about 5 minutes and building some dev images and pruning them again. I then shutdown wsl and enabled sparse on docker-desktop as well. Again rebuilding images and pruning did not change the vhdx's filesize. (I did this thinking that generating some activity on the filesystem could kick in the vhd optimizing).

For good measure I shutdown and restarted wsl once more.

Should I expect the vhdx to be smaller after these actions?

The file I am looking at is "C:\Users\x\AppData\Local\Docker\wsl\data\ext4.vhdx" and its size is the same (123 GB) as before I updated WSL today. The first prune, before enabling sparse on docker-desktop-data, said Total reclaimed space: 64.22GB.

mmarinchenko commented 1 year ago

@daniel5gh I haven't tested this myself, but I guess you should also prune the docker build cache.

See https://docs.docker.com/engine/reference/commandline/builder_prune/

You can also try the Disk Usage extension to do the same in the Docker Desktop GUI: https://hub.docker.com/extensions/docker/disk-usage-extension

daniel5gh commented 1 year ago

@mmarinchenko Thank you for your suggestion, but I think docker prune --all should also reclaim the build cache, judging from its output:

WARNING! This will remove:
  - all stopped containers
  - all networks not used by at least one container
  - all images without at least one container associated to them
  - all build cache

Are you sure you want to continue? [y/N] y

I will give the Disk Usage extension a go, haven't used that before. thanks. The output from this extension is in line with my expectations:

2.23 GB images, the ones I just built. 27.25 GB volumes, 2.89 MB build cache.

mmarinchenko commented 1 year ago

@daniel5gh You're right, I just didn't realize you were using system prune from your comment aboveπŸ‘

If docker system df shows the same thing (0% reclaimable space), then I join your question) Thanks for testing!

polarathene commented 1 year ago

docker-desktop-data --set-sparse true specific troubleshooting

TL;DR:

After the purge, the data disk .vhdx was now 1.4GB, which seems to match the /mnt/wsl/docker-desktop-data below. Nothing else changed related to the other docker locations.


Yes to clarify you would need to run it for your given distro. please run wsl --manage docker-desktop-data --set-sparse true and you should see it now shrink in size automatically.

# Curious if this would return disk-space that had since been freed:
$ wsl.exe --manage docker-desktop-data --set-sparse true
Conversion in progress, this may take a few minutes.
The operation completed successfully.

# Confirm filepath:
$ (Get-ChildItem -Path HKCU:\Software\Microsoft\Windows\CurrentVersion\Lxss | Where-Object { $_.GetValue("DistributionName") -eq 'docker-desktop-data' }).GetValue("BasePath") + "\ext4.vhdx"
\\?\C:\Users\polarathene\AppData\Local\Docker\wsl\data\ext4.vhdx
# Checking disk size after making the file sparse:

$ ls -lh /mnt/c/Users/polarathene/AppData/Local/Docker/wsl/data/ext4.vhdx
-rwxrwxrwx 1 polarathene polarathene 35G Sep 24 19:55 /mnt/c/Users/polarathene/AppData/Local/Docker/wsl/data/ext4.vhdx

$ du -h /mnt/c/Users/polarathene/AppData/Local/Docker/wsl/data/ext4.vhdx
27G     /mnt/c/Users/polarathene/AppData/Local/Docker/wsl/data/ext4.vhdx

$ du --si /mnt/c/Users/polarathene/AppData/Local/Docker/wsl/data/ext4.vhdx
29G     /mnt/c/Users/polarathene/AppData/Local/Docker/wsl/data/ext4.vhdx

$ du --bytes -h /mnt/c/Users/polarathene/AppData/Local/Docker/wsl/data/ext4.vhdx
35G     /mnt/c/Users/polarathene/AppData/Local/Docker/wsl/data/ext4.vhdx

$ du --bytes --si /mnt/c/Users/polarathene/AppData/Local/Docker/wsl/data/ext4.vhdx
37G     /mnt/c/Users/polarathene/AppData/Local/Docker/wsl/data/ext4.vhdx

# From du --help:
--apparent-size
print apparent sizes, rather than disk usage; although the apparent size is usually smaller,
it may be larger due to holes in ('sparse') files, internal fragmentation, indirect blocks, and the like
-b, --bytes
equivalent to '--apparent-size --block-size=1'
-h, --human-readable
print sizes in human readable format (e.g., 1K 234M 2G)
--si
like -h, but use powers of 1000 not 1024

From Windows Explorer, right-click => properties:

NOTE: Above information was collected after the first attempt with sparse not freeing any space (C:\ was at 3GB disk space left remaining).

Despite that, it's unclear what else is using 26GB for a volume that's supposedly only data for Docker?

# Absolutely cleared all user data:

$ docker builder du
Reclaimable:    0B
Total:          0B

$ docker builder prune -a
WARNING! This will remove all build cache. Are you sure you want to continue? [y/N] y
Total:  0B

$ docker system df
TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
Images          0         0         0B        0B
Containers      0         0         0B        0B
Local Volumes   0         0         0B        0B
Build Cache     0         0         0B        0B

$ docker system prune -a
WARNING! This will remove:
  - all stopped containers
  - all networks not used by at least one container
  - all images without at least one container associated to them
  - all build cache

Are you sure you want to continue? [y/N] y
Total reclaimed space: 0B

$ docker volume ls
DRIVER    VOLUME NAME

$ docker volume prune -a
WARNING! This will remove all local volumes not used by at least one container.
Are you sure you want to continue? [y/N] y
Total reclaimed space: 0B
# Presumably some of this is used
$ du -sh /usr/local/lib/docker/
40K     /usr/local/lib/docker/

$ du -h --max-depth=2 /Docker
221M    /Docker/host/bin
248M    /Docker/host/cli-plugins
674M    /Docker/host/wsl
2.5G    /Docker/host
2.5G    /Docker

$ du -h /mnt/wsl/docker-desktop-data
0       /mnt/wsl/docker-desktop-data/data
443M    /mnt/wsl/docker-desktop-data/isocache/entries/docker-wsl-cli.iso
171M    /mnt/wsl/docker-desktop-data/isocache/entries/docker-for-wsl.iso
747M    /mnt/wsl/docker-desktop-data/isocache/entries/services.iso
1.4G    /mnt/wsl/docker-desktop-data/isocache/entries
1.4G    /mnt/wsl/docker-desktop-data/isocache
1.4G    /mnt/wsl/docker-desktop-data

$ df -h | grep -i docker
/dev/sde       1007G  1.4G  955G   1% /mnt/wsl/docker-desktop-data/isocache
none            7.7G   12K  7.7G   1% /mnt/wsl/docker-desktop/shared-sockets/host-services
/dev/sdd       1007G   61M  956G   1% /mnt/wsl/docker-desktop/docker-desktop-user-distro
/dev/loop0      443M  443M     0 100% /mnt/wsl/docker-desktop/cli-tools
drvfs           450G  439G   12G  98% /Docker/host

You can also try the Disk Usage extension to do the same in the Docker Desktop GUI: https://hub.docker.com/extensions/docker/disk-usage-extension

Nothing in use as expected from above:

image


Perhaps there are some other options to explore here (not too keen to read through 180+ hidden messages though).

It doesn't look like docker-desktop-data VHDX is actually using 26GB, I don't have the disk space free to explore some of those and since I've already thrown all my actual docker data away, I might as well go with the GUI purge option πŸ€·β€β™‚οΈ

image

image

Success!

$ du --bytes --si /mnt/c/Users/polarathene/AppData/Local/Docker/wsl/data/ext4.vhdx
1.6G    /mnt/c/Users/polarathene/AppData/Local/Docker/wsl/data/ext4.vhdx

Obviously not ideal to purge the entire docker-desktop-data. Next time I'll try another workaround for compacting the vhdx.

NOTE: I had also discovered C:\Users\polarathene\AppData\Local\Temp\docker-scout\sha256 using 11GB from having "Experimental Features" enabled, but never having interacted with the Docker Scout tab/feature. I probably did enable experimental features; I had removed this 11GB prior to the GUI purge, but noticed nothing reclaimed from the VHDX (as expected).


Off-topic WSL2 + Docker feedback I've been a Linux user for many years, but recently giving Windows 11 a try for a few months to see what I'm missing out on. Prior to trying WSL2 I had been using VMware Player on Windows to run a Linux guest with Docker and that had been going quite smoothly. I wanted to try the Docker Desktop app on the Windows host and was also curious about WSL2. - I was a bit surprised to find this prevented accessing my existing VMs (_unless I lose their suspend state and disable the virtualization CPU `VT-x` / `AMD-V` feature_). Alternatively I have to disable WSL2 (_with that apparently involving a registry edit and reboot, or similar inconvenient ways to switch_). - Memory usage with file cache was another gripe, but glad to see that's being addressed, just not yet compatible with Docker πŸ˜… (_also a little surprised that cgroups v2 isn't available?_) Personally, not a positive experience with WSL2 so far, but I'm glad to see it's improving πŸ’ͺ
onomatopellan commented 1 year ago

@polarathene wow thanks for this. I was getting nuts trying sparseVhd=true and seeing the vhdx file size was always the same in Windows Explorer even after deleting GBs of data but now I see it's displayed in "size on disk" and eventually in This Pc.

mmarinchenko commented 1 year ago

@polarathene

  • I was a bit surprised to find this prevented accessing my existing VMs (unless I lose their suspend state and disable the virtualization CPU VT-x / AMD-V feature). Alternatively I have to disable WSL2 (with that apparently involving a registry edit and reboot, or similar inconvenient ways to switch).

Yes, that's because Hyper-V (and therefore WSL2) is actually a native hypervisor. This means that when you enable Hyper-V/WSL2, your Windows "host" actually becomes a privileged guest relative to the virtualization layer. And after that, other installed virtualization solutions (such as VMware for Windows, which is a hosted hypervisor) lose access to hardware virtualization support, since this now requires that Hyper-V nested virtualization be enabled and supported by these solutions (VMware Player, in your case).

mmarinchenko commented 1 year ago

My guess is that docker system prune -af just drops the ext4 inodes (as expected). And for the sparse VHD feature, this is not enough, because the actual VHD space is not zeroed.

daniel5gh commented 1 year ago

Just adding this in case it is useful for anyone.

And for the sparse VHD feature, this is not enough, because the actual VHD space is not zeroed.

The other day I also tried filling unused space in the ext4 fs with zeroes, basically as a wild guess. It did not have an effect on the vhdx filesize

# (wsl -d docker-desktop)
# based on disk size and used size I assumed this is the right filesystem
cat /dev/zero > /tmp/docker-desktop-root/mnt/host/wsl/docker-desktop-data/version-pack-data/community/docker/overlay2/zero
# until output cat: write error: No space left on device
rm /tmp/docker-desktop-root/mnt/host/wsl/docker-desktop-data/version-pack-data/community/docker/overlay2/zero

I don't know what is needed for the vhdx sparse feature, but the above did not seem to do that.

vbrozik commented 1 year ago

And for the sparse VHD feature, this is not enough, because the actual VHD space is not zeroed.

Correct implementation of this functionality should use the trim command of the disk interfaces which has been supported in Linux for many years already. There are multiple articles about this on the internet, for example: How to Enable TRIM For SSD in Ubuntu

Unfortunately the WSL release blog says absolutely nothing about how the OS should indicate which disk blocks should be freed: Automatic disk space clean up (Set sparse VHD)

RandomDSdevel commented 1 year ago

Hi folks, we have just put out a new experimental feature in WSL that aims to address this in the latest update. You can now run wsl --manage <distroName> --set-sparse true to set it to a sparse VHD that will automatically reclaim memory. This will allow it to shrink in size as you use it!

More info on this release and the changes can be found here in the blog post. Please tell us what you think!

     Awesome! Does this work with WSL 2 instance whose VHD images have had NTGS compression applied to them on the Windows side, too?

     I tried it after I finally managed to get the 2.0.0 pre-release package to show up and install, and everything works like a charm!

(Edit: See my comment below.)


Correct implementation of this functionality should use the trim command of the disk interfaces which has been supported in Linux for many years already. There are multiple articles about this on the internet, for example: How to Enable TRIM For SSD in Ubuntu

Unfortunately the WSL release blog says absolutely nothing about how the OS should indicate which disk blocks should be freed: Automatic disk space clean up (Set sparse VHD)

     There's an 'fstrim' command in util-linux that you can use to trigger this manually in the meantime.

Gerben321 commented 1 year ago

I could really use some help with this. I noticed today my Docker was acting weird and restarting. I couldn't get it properly working and directly noticed my whole 512GB SSD was filled. With further investigation it seemed that my C:\Users\%user%\AppData\Local\Docker\wsl\data\ext4.vhdx has grown to almost 350GB. I've tried everything, clean Docker stuff, but that's only 15GB in total, and use the diskpart or optimize-vhd command. Both don't seem to do anything. Looking at my Ubuntu distro, it's using around 35GB.

I then tried the sparse option introduced in the new WSL, hoping that that would fix it. But also nothing, still the same size. Sadly I can't really do anything else since I have only 4-5GB left on my SSD. I hope I don't have to start from scratch!

ghost commented 1 year ago

@Gerben321, as @RandomDSdevel mentioned above you, if you change to sparse after not having been sparse, you'd need to run sudo fstrim -v /. Setting it to sparse only means that going forward empty space is reclaimed as it is produced. It doesn't have an effect on what happened in the past unless you use something fstrim to clean up after the fact.

So long as you see the discard option under findmnt -l / you should be seeing space reclaimed on the host when it is freed on the guest (inside wsl).

talves commented 1 year ago

[[Failed]] I'm not seeing the size of the .vhdx file change using fstrim -v / although I know everything is setup correctly. Using Win10.

I'm going to set sparse back to false and run DiskPart to compact the disk and see if I can reclaim the size back down, then turn sparse back on and see if it works. I don't mind doing this if I need to, just don't want to deal with a 500G .vhdx file.

Results:

Unfortunately the above corrupted the instance and no longer allowed for connection from WSL using the pre-release [[Worked]] I restored my non-sparse backup of the above large .vhdx distro. Launched WSL and cleaned up everything I didn't need (approx. 150G) which included a ton of Rust compiled debug code targets as well as using docker prune -a.

Note: I had already upgraded the pre-release, so not sure if that is why DiskPart kept messing up the distro when using the compact command.

ghost commented 1 year ago

There are two different sizes. Setting sparse will only reduce the "Size on disk"

image
talves commented 1 year ago

@pmartincic I understand this. Both those numbers are the same in my case.

Are we saying once the Size on disk increases, it never recovers space even if we use sparse=true? I was saying above that it never recovered space once I removed files with sparse turned on.

polarathene commented 1 year ago

Are we saying once the Size on disk increases, it never recovers space even if we use sparse=true? I was saying above that it never recovered space once I removed files with sparse turned on.

My earlier comment explains what to expect.

darkvertex commented 1 year ago

Out of curiosity does sparse mode only clear the equivalent deleted data size after enabling or does it go through the whole disk?

Let me rephrase that... If I have a WSL disk I've been using for a year (so there's definitely some unreleased empty space), write a 100MB file, enable spare mode and delete that 100MB file, can I reasonably expect the "size on disk" to shrink more than the 100MB difference since enabling it?

dgw commented 1 year ago

@darkvertex Look a few comments above yours, less than 24 hours ago: https://github.com/microsoft/WSL/issues/4699#issuecomment-1735824244

You'll want to use fstrim.

vbrozik commented 1 year ago

Can please anyone confirm that the new functionality "Automatic disk space clean up (Set sparse VHD)" is based on the HDD trim command? Then we would know if it makes sense to use the fstrim command in Linux. It is a pity that we do not get this information from Microsoft. :(

yume-chan commented 1 year ago

https://github.com/microsoft/WSL/issues/4699#issuecomment-1735824244 is from a collaborator so I guess it's trustable?

I found https://learn.microsoft.com/en-us/windows-server/administration/performance-tuning/role/hyper-v-server/storage-io-performance#unmap-notification-integration which suggests sparse (a.k.a expandable or dynamic) vhdx uses SCSI unmap command to signal deleted files. From Google results fstrim can also issue unmap commands in addition to the trim commands.

talves commented 1 year ago

My earlier comment explains what to expect.

None of this applies to my situation. I have the sparse settings turned on and added 3G of files to a directory, then deleted them and the instance did NOT reclaim the Size on disk or change any sizes given when doing a du -sh on the mounts. Also fstrim had no affect also.

polarathene commented 1 year ago

@talves do you have a reproduction? Are you mounting your own .vhdx or is it created and mounted for you by software like Docker Desktop?


For Docker Desktop I used docker pull on some images to increase the disk size (and identify the mount point affected via df -h from that increase):

# Windows properties: "Size"
$ du --bytes -h /mnt/c/Users/polarathene/AppData/Local/Docker/wsl/data/ext4.vhdx
14G     /mnt/c/Users/polarathene/AppData/Local/Docker/wsl/data/ext4.vhdx

# Windows properties: "Size on disk" (potentially smaller):
$ du -h /mnt/c/Users/polarathene/AppData/Local/Docker/wsl/data/ext4.vhdx
13G     /mnt/c/Users/polarathene/AppData/Local/Docker/wsl/data/ext4.vhdx

# Partition, disk usage and mount-point:
$ df -h
/dev/sde       1007G  4.9G  951G   1% /mnt/wsl/docker-desktop-data/isocache

# Remove all the images pulled:
$ docker system prune -a
Total reclaimed space: 3.479GB

# No change:
$ du --bytes -h /mnt/c/Users/polarathene/AppData/Local/Docker/wsl/data/ext4.vhdx
14G     /mnt/c/Users/polarathene/AppData/Local/Docker/wsl/data/ext4.vhdx

# Reflects the change from deletion (C:\ free space increased by similar amount):
$ du -h /mnt/c/Users/polarathene/AppData/Local/Docker/wsl/data/ext4.vhdx
9.8G     /mnt/c/Users/polarathene/AppData/Local/Docker/wsl/data/ext4.vhdx

$ df -h
/dev/sde       1007G  1.4G  955G   1% /mnt/wsl/docker-desktop-data/isocache

# No benefit since data was freed from deletion:
$ sudo fstrim --all --verbose
/mnt/wsl/docker-desktop-data/isocache: 0 B (0 bytes) trimmed on /dev/sde
/: 0 B (0 bytes) trimmed on /dev/sdc

I made the Docker/wsl/data/ext4.vhdx file sparse when it was reporting 12G with --bytes, not realizing that was the wrong value to look at and should have been omitted πŸ˜… So it may have been 9.8G (not sure if Docker Desktop GUI purge setting removed the prior sparse setting)

The remaining space isn't going to free itself though, but you can see that it is possible to track the change. Not sure why that wouldn't work for you. If you have a reproduction without Docker that'd be helpful πŸ‘


UPDATE

df -h vs du -sh

Observation with the /mnt/wsl/docker-desktop-data/isocache mount point.

While df -h reflects actual disk usage, if you use du -h on that mount point it seems you'll always get the base 1.4G size? (for the docker-desktop-data disk):

# Actual allocated (sparse) size on disk:
$ du -h /mnt/c/Users/polarathene/AppData/Local/Docker/wsl/data/ext4.vhdx
13G     /mnt/c/Users/polarathene/AppData/Local/Docker/wsl/data/ext4.vhdx

# Will grow as needed regardless as a dynamic sized vhdx (1TB max):
$ du -h --bytes /mnt/c/Users/polarathene/AppData/Local/Docker/wsl/data/ext4.vhdx
17G     /mnt/c/Users/polarathene/AppData/Local/Docker/wsl/data/ext4.vhdx

# Actual size of filesystem recognized:
# This is 1.4G originally, which matches the on-disk size when Docker Desktop purges (recreates) the disk:
# While allocated size above with sparse enabled 
$ df -h /mnt/wsl/docker-desktop-data/isocache
Filesystem      Size  Used Avail Use% Mounted on
/dev/sde       1007G  4.7G  952G   1% /mnt/wsl/docker-desktop-data/isocache

# Does not reflect "Used" from `df -h`:
# (_NOTE: Despite the `.iso`, these are actually directories_)
$ du -h /mnt/wsl/docker-desktop-data/isocache/entries
443M    /mnt/wsl/docker-desktop-data/isocache/entries/docker-wsl-cli.iso
171M    /mnt/wsl/docker-desktop-data/isocache/entries/docker-for-wsl.iso
747M    /mnt/wsl/docker-desktop-data/isocache/entries/services.iso
1.4G    /mnt/wsl/docker-desktop-data/isocache/entries
Additional disk info ```console # Alternative view of volumes and mount paths $ lsblk --output NAME,FSTYPE,FSUSED,MOUNTPOINTS NAME FSTYPE FSUSED MOUNTPOINTS loop0 442.1M /mnt/wsl/docker-desktop/cli-tools loop1 loop2 sda ext4 sdb swap [SWAP] sdc ext4 1.9G /snap /mnt/wslg/distro / sdd ext4 60M /mnt/wsl/docker-desktop/docker-desktop-user-distro sde ext4 4.6G /mnt/wsl/docker-desktop-data/isocache # Discard info by block device: $ lsblk --discard NAME DISC-ALN DISC-GRAN DISC-MAX DISC-ZERO loop0 0 4K 4G 0 loop1 0 4K 4G 0 loop2 0 4K 4G 0 sda 0 2M 4G 0 sdb 0 1M 4G 0 sdc 0 1M 4G 0 sdd 0 1M 4G 0 sde 0 1M 4G 0 $ blkid | sort /dev/loop0: BLOCK_SIZE="2048" UUID="2023-09-05-22-13-09-00" LABEL="wsl-cli-bundle" TYPE="iso9660" /dev/loop1: BLOCK_SIZE="2048" UUID="2023-09-06-09-01-55-00" LABEL="LinuxKit" TYPE="iso9660" /dev/loop2: BLOCK_SIZE="2048" UUID="2023-09-08-08-27-11-00" LABEL="LinuxKit" TYPE="iso9660" /dev/sda: BLOCK_SIZE="4096" TYPE="ext4" /dev/sdb: UUID="8e89b770-22b7-4a39-9cf7-1f791ccb7a8e" TYPE="swap" /dev/sdc: UUID="c761ebae-d063-4066-9b1d-24109bcf3fc7" BLOCK_SIZE="4096" TYPE="ext4" /dev/sdd: UUID="a67e7733-e2f6-4d10-81df-90a950b18638" BLOCK_SIZE="4096" TYPE="ext4" /dev/sde: UUID="42c480a4-cf9a-4043-976e-ade3f8dc5beb" BLOCK_SIZE="4096" TYPE="ext4" # Only 1 of those loop devices is mounted $ cat /proc/mounts | grep loop /dev/loop0 /mnt/wsl/docker-desktop/cli-tools iso9660 ro,relatime,nojoliet,check=s,map=n,blocksize=2048,iocharset=iso8859-1 0 0 # Some tmpfs mounts in play: # /mnt/wsl/docker-desktop-data/isocache is mounted with `discard` option, so fstrim is not needed for the sparse vhdx: $ cat /proc/mounts | grep docker /dev/sde /mnt/wsl/docker-desktop-data/isocache ext4 rw,relatime,discard,errors=remount-ro,data=ordered 0 0 none /mnt/wsl/docker-desktop/shared-sockets/guest-services tmpfs rw,nosuid,nodev,mode=755 0 0 none /mnt/wsl/docker-desktop/shared-sockets/host-services tmpfs rw,nosuid,nodev,mode=755 0 0 /dev/sdd /mnt/wsl/docker-desktop/docker-desktop-user-distro ext4 rw,relatime,discard,errors=remount-ro,data=ordered 0 0 /dev/loop0 /mnt/wsl/docker-desktop/cli-tools iso9660 ro,relatime,nojoliet,check=s,map=n,blocksize=2048,iocharset=iso8859-1 0 0 none /mnt/wsl/docker-desktop-bind-mounts/Ubuntu/71329c4cc6e32171553fa81d044eb31d1a3aac52ba9376c4a99f4505c494cf5b tmpfs rw,nosuid,nodev,mode=755 0 0 $ ps -ax | grep docker 1035 pts/2 Ssl+ 0:00 /mnt/wsl/docker-desktop/docker-desktop-user-distro proxy --distro-name Ubuntu --docker-desktop-root /mnt/wsl/docker-desktop C:\Program Files\Docker\Docker\resources 1053 pts/4 Ssl+ 0:00 docker serve --address unix:///home/polarathene/.docker/run/docker-cli-api.sock ```

Observation with disk usage that seems tied to file cache

TL;DR: 3GB was written to docker-desktop-data disk, but 5GB in the file buffer cache (free -m) seemed to use disk space, not just memory? This was freed after quitting both Docker Desktop and the WSL2 terminal that ran the docker build command (wsl --shutdown speed up the process of reclaiming diskspace).

I have C:\ with 30GB of disk space free currently:


wslcompact pipes an export into an import

I also noticed that wslcompact is a convenience wrapper for wsl --export + wsl --import, and trying that failed for me, not because of disk-space, but because I lacked enough RAM. After the failure, PowerShell continued to hold 8GB of memory until I closed that terminal tab. The .vhdx to convert had 8.3GB "size on disk" (but otherwise seen as 16.8GB "size")

The following attempt also used 5GB of disk during that import + export operation (disk reclaimed after the failure automatically, memory didn't):

# Shutdown first to avoid causing any accidental corruption during the operation:
$ wsl --shutdown

# Export to stdout, pipe into import with the WSL vhdx location set to `$temp\wslcompact`.
# Temp location resolved to `C:\Users\polarathene\AppData\Local\Temp\wslcompact`
$ wsl --export docker-desktop-data - | wsl --import docker-desktop-data-compacted "$Env:TEMP\wslcompact" -

Import in progress, this may take a few minutes.Program 'wsl.exe' failed to run: Exception of type 'System.OutOfMemoryException' was thrown.At line:1 char:38
+ ... op-data - | wsl --import docker-desktop-data-compacted "$Env:TEMP\wsl ...
+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~.
At line:1 char:1
+ wsl --export docker-desktop-data - | wsl --import docker-desktop-data ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ResourceUnavailable: (:) [], ApplicationFailedException
    + FullyQualifiedErrorId : NativeCommandFailed

Manual compaction with wsl --export + wsl --import

UPDATE: If I don't use the pipe, the wsl --export and wsl --import commands are relatively fast and don't use anywhere near as much memory. I get the expected 1.4GB size as a .tar file, and after using wsl --import the new location creates a 1.4GB .vhdx as well.

Obviously wslcompact itself would be easier to use, but here's a step-by-step series of commands you can run directly in PowerShell:

# Prepare steps
# Export / Import files will use this location:
$tmp_folder = "$Env:TEMP\wsl-workaround-dir"
# Only required if the `.tar` export folder does not exist:
New-Item -Path "$tmp_folder" -Type Directory -Force
# Grab the vhdx path for docker-desktop-data:
$wsl_distro_path = (Get-ChildItem -Path HKCU:\Software\Microsoft\Windows\CurrentVersion\Lxss | Where-Object { $_.GetValue("DistributionName") -eq 'docker-desktop-data' }).GetValue("BasePath") + "\ext4.vhdx"

# Export as compressed tar, then run export to create the compacted vhdx file:
wsl --shutdown
wsl --export docker-desktop-data "$tmp_folder\exported.tar"
wsl --import workaround-compacted "$tmp_folder\compacted\" "$tmp_folder\exported.tar"

# Overwrite the existing ext4.vhdx for docker-desktop-data:
wsl --shutdown
Move-Item "$tmp_folder\compacted\ext4.vhdx" "$wsl_distro_path" -Force
# Cleanup - These are no longer needed:
wsl --unregister workaround-compacted
remove-item "$tmp_folder/exported.tar" -Force

# Enable sparse again:
wsl --manage docker-desktop-data --set-sparse true

fstrim

I did a trim after all this with another export+import but without the sparse setting applied. Did the docker build, which increased the 1.4GB vhdx to 5GB, and docker system prune -a afterwards to delete it all.

Interestingly no trim benefit on that docker disk (/dev/sde), but it claims to have trimmed 1TB from /dev/sdc (host disk is 500GB):

$ sudo fstrim --all --verbose
/mnt/wsl/docker-desktop-data/isocache: 0 B (0 bytes) trimmed on /dev/sde
/: 1004.6 GiB (1078706663424 bytes) trimmed on /dev/sdc

The vhdx remains at 5GB. Afterwards I made the docker-desktop-data vhdx sparse once more, and we see the same behaviour:

$ sudo fstrim --all --verbose
/mnt/wsl/docker-desktop-data/isocache: 1005.5 GiB (1079655772160 bytes) trimmed on /dev/sde
/: 1004.6 GiB (1078685446144 bytes) trimmed on /dev/sdc

The space was not reclaimed though πŸ€·β€β™‚οΈ

Closing WSL and using wsl --shutdown, then opening that up again (and starting Docker Desktop after), the trim command can be run again with the same effect. Bit misleading πŸ€”

onomatopellan commented 1 year ago

@talves Just finished testing and sparseVhd doesn't work if the vhdx file is in a mechanical HDD. Make sure the vhdx file resides in a SDD in order to see Size on disk decreasing.

mmarinchenko commented 1 year ago

sparseVhd doesn't work if the vhdx file is in a mechanical HDD

Oh. If it's done intentionally, it should be documented.

talves commented 1 year ago

@polarathene it's not a docker issue. It's just compiling code for Rust and the files it creates (2G) are deleted. That's the reproduction.

@onomatopellan Yeah, it's a Solid State Drive.

The issue might be that it's on a windows 10 OS. I can't confirm that, because it's only people in comments on the release blog saying that. I haven't seen official statements about it.

WSL version: 2.0.1.0
Kernel version: 5.15.123.1-1
WSLg version: 1.0.58
MSRDC version: 1.2.4485
Direct3D version: 1.608.2-61064218
DXCore version: 10.0.25880.1000-230602-1350.main
Windows version: 10.0.19045.3448

I would just like to revert to the latest non pre-release, if that's possible. This has been a loss of time I wish I never tried.