The reason I have wandered down this road is that the one reson I always stuck with WSL1 is its filesystem performance when working with files on the windows system.
I recently decided to jump to WSL2 due to some of its many features, but was horribly hampered by just how slow it was to interact with Windows files. A lot of my development is for Android and I run Android Studio on my computer but interact with the repo using WSL to manage Git and to sometimes run the Unit Tests. When I switched to WSL2, git ground to a halt. I was seeing typically everything taking 10x more time to complete. Running git status in WSL1 would take 0.5s or less. In WSL2 it takes 6.5 seconds on average, or 23+ seconds if it had to reindex the 1549 files in the project, which only tooke WSL1 about 2.7 seconds to complete previously.
I began searching around for a solution to this file interoperability problem and found many people saying NFS would work. Well it didn't. Since I don't have Windows 11 Pro, I don't get the fun NFS feature that was previously available in the Home version (they removed it for money I guess).
So I tried the third-party programs: FreeNFS, haneWin NFS, and some other winnfsd.exe program I found online. Sometimes I could get my local WSL2 mount to work, but then it would die after some small amount of time, causing the terminal to hang. Other time it just wouldn't connect and just hang or timeout, and good luck getting it to connect on boot with fstab!
So the problem I was facing was trying to rely on a Linux-based feature to run reliably on Windows (a NFS server). So I started looking into alternatives, that's when I saw some articles about mounting a Windows Samba share. Again I ran into many issues and couldn't get a local linux samba client to connect to my windows host machine.
The next big issue is that WSL2 runs inside of a special Hyper-V container. This means that it no longer shares the Windows NIC and localhost. Instead it is randomly assigned a new local IP address within the Hyper-V virtual network. This IP is in the 172.16.0.0/12 subnet. This leaves you with two options:
- Connect to my local network IP, thereby routing through my nearest WiFi router/Network Switch (in my case 192.168.1.101)
- Fetch my Windows Host machine's IP on the virtual network and connect to that.
With Option 1, you can add the mount to /etc/fstab and have it auto-mounted by the system. But it won't work if you change networks and get a different local IP.
With Option 2, you cannot add it to /etc/fstab but instead you can add it to your user's ~/.bashrc file to auto mount on start up. This protects against dynamic host IP, but must be in each WSL2 user's .bashrc to insure it is run.
I found someone online suggest to use CIFS. And it WORKED! There were some steps, and some issues with WSL2 IP, but now it works great. So I want to share with others how I went about getting this to work.
- Open
Settings -> Network & internet -> Advanced network settings -> Advanced sharing settings - Under
Private networks, toggle ONNetwork discoveryandFile and printer sharing, and check ONSet up network connected devices automatically - Under
All networks, toggle ONPassword-protected sharing
Later you will have to store windows login credentials within the WSL2 files, so if you are concerned about leaving a plain-text password on your computer, I suggest you create a local user for this connection. Otherwise continue to stage 3
NOTE: Microsoft REALLY hates you making local users, so follow the steps carefully
- Open
Settings -> Accounts -> Other Users - Click the
Add accountbutton - Click the
I don't have this person's sign-in informationlink - Click the
Add a user without a Microsoft accountlink - Enter a username and password (I just use CIFS and cifs respectively) into the fields and enter some security questions. (You can just fill them all with the same answer)
- click
Next
Next you want to share the folders on your network so that WSL2 can find and mount them.
So for each folder you wish to mount, do the following:
- Navigate to the folder in explorer
- Open the folder's properties, and click the
Sharingtab - Click
Sharebutton - If you created a local user in Stage 2, follow these steps to add them. Otherwise proceed to step 5.
- Select them from the drop-down menu and click
Add - Then click the
Readdropdown menu to the right of the user in the list and selectRead/Write
- Select them from the drop-down menu and click
- Click
Shareand wait for it to complete. Then clickDoneand close the folder properties window.
- Open the folder's properties dialog and click the
Sharingtab - Click
Advanced Sharing... - Uncheck
Share this folder - Click
OKand close the folder properties dialog.
Run the following commands to install CIFS:
sudo apt update
sudo apt install cifs-utils(UPDATE 09/2023) Please see Update below if you are using Mirrored Network.
You can fetch the host IP using ip route and extracting the default via IP from the result. To do this we can use grep and sed.
$ ip route
default via 172.25.208.1 dev eth0 proto kernel
172.25.208.0/20 dev eth0 proto kernel scope link src 172.25.217.253
$ ip route | grep "default via" | sed -En 's/[^0-9]*([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}).*/\1/p'`
172.25.208.1By default, the system will mount the drive under the root user, which means you'll have to sudo everything. Instead you can specify which user and which group will be the default for the mount. This is done using the user and group ids.
$ id -u flame
1000
$ id -g flame
1000You could also create a special group for the CIFS mounts so that multiple users could access it via group permissions.
The core command for mounting the drive is as follows:
# for local user 'CIFS' with password 'cifs' (if you created one in Stage 2)
sudo mount -t cifs //172.25.208.1/MyFolder /mnt/my-folder -o username=CIFS,password=cifs,uid=1000,gid=1000
# for microsoft account 'myemail@live.com' with password 'HelloWorld'
sudo mount -t cifs //172.25.208.1/MyFolder /mnt/my-folder -o username=myemail,domain=live.com,password=HelloWorld,uid=1000,gid=1000This follows the pattern mount -t <type> <remote-folder> <local-folder> -o <options>
(UPDATE 09/2023) Please see Update below if you are using Mirrored Network.
We can then combine all of this work into the following and add it to our ~/.bashrc
# file: ~/.bashrc
# Fetch our Windows Host IP
WIN_HOST_IP=`ip route | grep default | sed -En 's/[^0-9]*([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}).*/\1/p'`
# Set our local user credentials
WIN_HOST_USER="CIFS" # Username of local user, or the user portion of a Microsoft Account email address
WIN_HOST_PASS="cifs"
# If you are using a Microsoft Account, uncomment and assign the domain portion of your email address
#WIN_HOST_DOMAIN="live.com"
# Fetch the current user's uid and gid.
WSL_UID=`id -u`
WSL_GID=`id -g` # You can use `id -g my-group` if you want the id of a specific group
# Create a function we can call to make it easier to mount multiple folders
mount_cifs() {
# If the mount point is already in use, echo a notice and exit. You can remove the echo portion if it annoys you
mount | grep "$2" &>/dev/null && echo "$2: Already mounted" && return 1
# If the mount point folder does not exist, create it
if [ ! "$2" ]; then
sudo mkdir "$2"
fi
# (Local User) Comment out if using Microsoft Account
sudo mount -t cifs "//$WIN_HOST_IP/$1" "$2" -o "username=$WIN_HOST_USER,password=$WIN_HOST_PASS,uid=$WSL_UID,gid=$WSL_GID"
# (Microsoft User) Uncomment if using Microsoft Account
#sudo mount -t cifs "//$WIN_HOST_IP/$1" "$2" -o "username=$WIN_HOST_USER,password=$WIN_HOST_PASS,domain=$WIN_HOST_DOMAIN,uid=$WSL_UID,gid=$WSL_GID"
}
# Mount your folders
# mount_cifs <remote-folder-name> <mount-point-folder>
mount_cifs Work /mnt/work
mount_cifs Projects /mnt/projs
mount_cifs Other /some/folder/path/otherWith the update released in September 2023, you can now activate a Mirrored Network mode that allows WSL2 to share the same NIC as the host computer. This means we need to update our script if you have this feature enabled.
https://devblogs.microsoft.com/commandline/windows-subsystem-for-linux-september-2023-update/
With a mirrored network, we no longer need to discover our IP address, and instead we can just use the standard loopback IP 127.0.0.1. So we no longer need the How we Fetch Host IP) step.
Here is the updated script:
# file: ~/.bashrc
# Set our local user credentials
WIN_HOST_USER="CIFS" # Username of local user, or the user portion of a Microsoft Account email address
WIN_HOST_PASS="cifs"
# If you are using a Microsoft Account, uncomment and assign the domain portion of your email address
#WIN_HOST_DOMAIN="live.com"
# Fetch the current user's uid and gid.
WSL_UID=`id -u`
WSL_GID=`id -g` # You can use `id -g my-group` if you want the id of a specific group
# Create a function we can call to make it easier to mount multiple folders
mount_cifs() {
# If the mount point is already in use, echo a notice and exit. You can remove the echo portion if it annoys you
mount | grep "$2" &>/dev/null && echo "$2: Already mounted" && return 1
# If the mount point folder does not exist, create it
if [ ! "$2" ]; then
sudo mkdir "$2"
fi
# (Local User) Comment out if using Microsoft Account
sudo mount -t cifs "//127.0.0.1/$1" "$2" -o "username=$WIN_HOST_USER,password=$WIN_HOST_PASS,uid=$WSL_UID,gid=$WSL_GID"
# (Microsoft User) Uncomment if using Microsoft Account
#sudo mount -t cifs "//127.0.0.1/$1" "$2" -o "username=$WIN_HOST_USER,password=$WIN_HOST_PASS,domain=$WIN_HOST_DOMAIN,uid=$WSL_UID,gid=$WSL_GID"
}
# Mount your folders
# mount_cifs <remote-folder-name> <mount-point-folder>
mount_cifs Work /mnt/work
mount_cifs Projects /mnt/projs
mount_cifs Other /some/folder/path/other
❤️