Windows Version
Microsoft Windows [Version 10.0.19045.6466]
WSL Version
2.6.3.0 (the root-cause analysis below is based on current master, where the logic is unchanged)
Are you using WSL 1 or WSL 2?
Kernel Version
6.6.87.2-1
Distro Version
Ubuntu 24.04.2 LTS
Other Software
None
Repro Steps
- In a WSL2 distro, set
/etc/wsl.conf to:
[automount]
enabled = false
mountFsTab = false
- Run
wsl --shutdown to apply the change.
- Start the distro again and try to access
\\wsl.localhost\<distro> (or \\wsl$\<distro>) from Windows.
Expected Behavior
The Linux filesystem is accessible from Windows. Per the documentation, automount.enabled and automount.mountFsTab only control automatic mounting of Windows drives and the processing of /etc/fstab. No coupling between these options and the 9p file server is documented.
Actual Behavior
\\wsl.localhost\<distro> and \\wsl$\<distro> are inaccessible:
PS C:\Users\Administrator> ls \\wsl.localhost\Ubuntu\home
ls : Cannot find path '\\wsl.localhost\Ubuntu\home' because it does not exist.
+ CategoryInfo : ObjectNotFound: (\\wsl.localhost\Ubuntu\home:String) [Get-ChildItem], ItemNotFoundException
+ FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand
(Original console output was localized; this is the equivalent English message.)
Inside the distro:
ps -ef | grep -i plan9 shows no plan9 process.
dmesg contains no plan9-related errors — init skips starting the server rather than failing to start it (see root cause below).
Setting either of the two options back to true makes the plan9 process appear and restores \\wsl.localhost access.
Root cause
In ConfigInitializeInstance() (src/linux/init/config.cpp), the call to StartPlan9Server() is guarded by:
unsigned int Plan9Port = LX_INIT_UTILITY_VM_INVALID_PORT;
if ((WI_IsFlagClear(Config.FeatureFlags.value(), LxInitFeatureDisable9pServer)) && (Config.Plan9Enabled) &&
(Config.AutoMount || Config.MountFsTab))
{
std::tie(Plan9Port, Config.Plan9ControlChannel) = StartPlan9Server(Plan9SocketPath, Config);
}
When both AutoMount and MountFsTab are false, the branch is skipped entirely, and Plan9Port is sent back to wslservice as LX_INIT_UTILITY_VM_INVALID_PORT in the LX_INIT_CONFIGURATION_INFORMATION_RESPONSE, so there is no server for the Windows side (p9rdr.sys via wslservice.exe) to connect to.
The comment above this block explains the rationale for the guard: the plan9 server needs a DrvFs mount for its socket file, so either fstab or automount must be enabled for that mount to be available. That rationale only holds for WSL1. On WSL2 (utility VM mode), StartPlan9Server() (src/linux/init/plan9.cpp) takes the vsock branch and never touches the socket path at all:
if (UtilIsUtilityVm())
{
sockaddr_vm address;
server.reset(UtilBindVsockAnyPort(&address, (SOCK_STREAM | SOCK_NONBLOCK)));
...
result = address.svm_port;
}
else
{
// Translate the socket path (store a copy for unlinking on shutdown).
translatedSocketPath = TranslatePath(const_cast<char*>(socketWindowsPath));
// Create the server socket.
server = CreateUnixServerSocket(translatedSocketPath.c_str());
}
So on WSL2 the server has no dependency on any DrvFs mount, and the guard is a WSL1-era constraint that unintentionally disables the 9p server on WSL2. Note also that a dedicated setting already exists for intentionally disabling the server (Config.Plan9Enabled), so whether the server runs shouldn't be implicitly decided by two mount-related options — a side effect that isn't documented anywhere.
Proposed fix
Exempt WSL2 from the mount requirement, keeping WSL1 behavior unchanged:
(UtilIsUtilityVm() || Config.AutoMount || Config.MountFsTab)
and update the comment to note that the DrvFs dependency only applies to WSL1. This is backward compatible: WSL1 behavior is unchanged, WSL2 is fixed.
Happy to submit a PR if this approach looks right.
Workaround
For anyone hitting this: keep mountFsTab = true together with enabled = false. As long as /etc/fstab contains no drvfs entries, mount -a is effectively a no-op, so no Windows drives get mounted, but the plan9 server starts normally.
Diagnostic Logs
An ETW trace was recorded with diagnostics/collect-wsl-logs.ps1 across a cold start of the distro (wsl --shutdown → start) followed by a failing \\wsl.localhost access. Since the repro above takes under a minute, I'm including only the relevant excerpt here for privacy; the full trace is available on request.
Excerpt from logs.etl, decoded with tracerpt logs.etl -o logs.csv -of CSV -y (provider WslCorePort). The hosts-file content embedded in the message is redacted and lines are re-wrapped for readability; otherwise unmodified:
SentMessage (wslservice → init):
Header = {MessageType = LxInitMessageInitialize MessageSize = 591 SequenceNumber = 1}
HostnameOffset = DESKTOP-DTB60UU DomainnameOffset = localdomain
WindowsHostsOffset = <redacted>
Plan9SocketOffset = TimezoneOffset = Asia/Taipei
DrvFsVolumesBitmap = 12 DrvFsDefaultOwner = 1000 FeatureFlags = 0 DrvfsMount = 2
ReceivedMessage (init → wslservice):
Header = {MessageType = LxInitMessageInitializeResponse MessageSize = 61 SequenceNumber = 2}
Plan9Port = 4294967295 DefaultUid = 1000 InteropPort = 3162867010
SystemdEnabled = 0 PidNamespace = 4026532221 FlavorIndex = ubuntu VersionIndex = 24.04
Plan9Port = 4294967295 is 0xFFFFFFFF, i.e. LX_INIT_UTILITY_VM_INVALID_PORT. With FeatureFlags = 0 (LxInitFeatureDisable9pServer not set) and the 9p server left enabled (default) in /etc/wsl.conf, the only clause of the guard that can have skipped StartPlan9Server() is (Config.AutoMount || Config.MountFsTab) — consistent with the analysis above. Note also the empty Plan9SocketOffset, confirming that WSL2 does not use a socket path (it uses vsock).
(The trace also shows an invalid Plan9Port for the system distro, FlavorIndex = mariner — that one is expected: unlike the Ubuntu distro, its LxInitMessageInitialize carries non-zero FeatureFlags = 20, and the system distro is never exposed via \\wsl$.)
Windows Version
Microsoft Windows [Version 10.0.19045.6466]
WSL Version
2.6.3.0 (the root-cause analysis below is based on current master, where the logic is unchanged)
Are you using WSL 1 or WSL 2?
Kernel Version
6.6.87.2-1
Distro Version
Ubuntu 24.04.2 LTS
Other Software
None
Repro Steps
/etc/wsl.confto:wsl --shutdownto apply the change.\\wsl.localhost\<distro>(or\\wsl$\<distro>) from Windows.Expected Behavior
The Linux filesystem is accessible from Windows. Per the documentation,
automount.enabledandautomount.mountFsTabonly control automatic mounting of Windows drives and the processing of/etc/fstab. No coupling between these options and the 9p file server is documented.Actual Behavior
\\wsl.localhost\<distro>and\\wsl$\<distro>are inaccessible:(Original console output was localized; this is the equivalent English message.)
Inside the distro:
ps -ef | grep -i plan9shows no plan9 process.dmesgcontains no plan9-related errors — init skips starting the server rather than failing to start it (see root cause below).Setting either of the two options back to
truemakes the plan9 process appear and restores\\wsl.localhostaccess.Root cause
In
ConfigInitializeInstance()(src/linux/init/config.cpp), the call toStartPlan9Server()is guarded by:When both
AutoMountandMountFsTabarefalse, the branch is skipped entirely, andPlan9Portis sent back to wslservice asLX_INIT_UTILITY_VM_INVALID_PORTin theLX_INIT_CONFIGURATION_INFORMATION_RESPONSE, so there is no server for the Windows side (p9rdr.sys via wslservice.exe) to connect to.The comment above this block explains the rationale for the guard: the plan9 server needs a DrvFs mount for its socket file, so either fstab or automount must be enabled for that mount to be available. That rationale only holds for WSL1. On WSL2 (utility VM mode),
StartPlan9Server()(src/linux/init/plan9.cpp) takes the vsock branch and never touches the socket path at all:So on WSL2 the server has no dependency on any DrvFs mount, and the guard is a WSL1-era constraint that unintentionally disables the 9p server on WSL2. Note also that a dedicated setting already exists for intentionally disabling the server (
Config.Plan9Enabled), so whether the server runs shouldn't be implicitly decided by two mount-related options — a side effect that isn't documented anywhere.Proposed fix
Exempt WSL2 from the mount requirement, keeping WSL1 behavior unchanged:
and update the comment to note that the DrvFs dependency only applies to WSL1. This is backward compatible: WSL1 behavior is unchanged, WSL2 is fixed.
Happy to submit a PR if this approach looks right.
Workaround
For anyone hitting this: keep
mountFsTab = truetogether withenabled = false. As long as/etc/fstabcontains no drvfs entries,mount -ais effectively a no-op, so no Windows drives get mounted, but the plan9 server starts normally.Diagnostic Logs
An ETW trace was recorded with
diagnostics/collect-wsl-logs.ps1across a cold start of the distro (wsl --shutdown→ start) followed by a failing\\wsl.localhostaccess. Since the repro above takes under a minute, I'm including only the relevant excerpt here for privacy; the full trace is available on request.Excerpt from
logs.etl, decoded withtracerpt logs.etl -o logs.csv -of CSV -y(providerWslCorePort). The hosts-file content embedded in the message is redacted and lines are re-wrapped for readability; otherwise unmodified:Plan9Port = 4294967295is0xFFFFFFFF, i.e.LX_INIT_UTILITY_VM_INVALID_PORT. WithFeatureFlags = 0(LxInitFeatureDisable9pServernot set) and the 9p server left enabled (default) in/etc/wsl.conf, the only clause of the guard that can have skippedStartPlan9Server()is(Config.AutoMount || Config.MountFsTab)— consistent with the analysis above. Note also the emptyPlan9SocketOffset, confirming that WSL2 does not use a socket path (it uses vsock).(The trace also shows an invalid
Plan9Portfor the system distro,FlavorIndex = mariner— that one is expected: unlike the Ubuntu distro, itsLxInitMessageInitializecarries non-zeroFeatureFlags = 20, and the system distro is never exposed via\\wsl$.)