Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
20 changes: 7 additions & 13 deletions src/linux/init/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1729,10 +1729,6 @@ Return Value:
if (strcmp(MountEnum.Current().FileSystemType, PLAN9_FS_TYPE) == 0)
{
MountSource = UtilParsePlan9MountSource(MountEnum.Current().SuperOptions);
if (MountSource.empty())
{
continue;
}
}
else if (strcmp(MountEnum.Current().FileSystemType, DRVFS_FS_TYPE) == 0)
{
Expand All @@ -1741,13 +1737,18 @@ Return Value:
}
else if (strcmp(MountEnum.Current().FileSystemType, VIRTIO_FS_TYPE) == 0)
{
MountSource = UtilParseVirtiofsMountSource(MountEnum.Current().Source);
MountSource = QueryVirtiofsMountSource(MountEnum.Current().Source);
}
else
{
continue;
}

if (MountSource.empty())
{
continue;
}

auto letter = ConfigGetDriveLetter(MountSource);
if (letter.has_value())
{
Expand Down Expand Up @@ -2445,17 +2446,10 @@ try
NewMountOptions += ',';
}

MountPlan9Filesystem(NewSource, MountEntry.MountPoint, NewMountOptions.c_str(), Message->Admin, Config);
MountPlan9Share(NewSource, MountEntry.MountPoint, NewMountOptions.c_str(), Message->Admin, Config);
}
else if (strcmp(MountEntry.FileSystemType, VIRTIO_FS_TYPE) == 0)
{
std::string_view Source = MountEntry.Source;
std::string_view OldTag = Message->Admin ? LX_INIT_DRVFS_VIRTIO_TAG : LX_INIT_DRVFS_ADMIN_VIRTIO_TAG;
if (!wsl::shared::string::StartsWith(Source, OldTag))
{
continue;
}

RemountVirtioFs(MountEntry.Source, MountEntry.MountPoint, MountEntry.MountOptions, Message->Admin);
}
else
Expand Down
211 changes: 143 additions & 68 deletions src/linux/init/drvfs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,70 +298,12 @@ try
{
return MountFilesystem(DRVFS_FS_TYPE, Source, Target, Options, ExitCode);
}

// Use virtiofs if the source of the mount is the root of a drive; otherwise, use 9p.
if (WSL_USE_VIRTIO_FS(Config))
{
if (wsl::shared::string::IsDriveRoot(Source))
{
return MountVirtioFs(Source, Target, Options, Admin, Config, ExitCode);
}

LOG_WARNING("virtiofs is only supported for mounting full drives, using 9p to mount {}", Source);
}

//
// Check if the path is a UNC path.
//

const char* Plan9Source;
std::string UncSource;
if ((strlen(Source) >= PLAN9_UNC_PREFIX_LENGTH) && ((Source[0] == '/') || (Source[0] == '\\')) &&
((Source[1] == '/') || (Source[1] == '\\')))
else if (WSL_USE_VIRTIO_FS(Config))
{
UncSource = PLAN9_UNC_TRANSLATED_PREFIX;
UncSource += &Source[PLAN9_UNC_PREFIX_LENGTH];
Plan9Source = UncSource.c_str();
}
else
{
Plan9Source = Source;
return MountVirtioFs(Source, Target, Options, Admin, Config, ExitCode);
}

//
// Check whether to use the elevated or regular 9p server.
//

bool Elevated = Admin.has_value() ? Admin.value() : IsDrvfsElevated();

//
// Initialize mount options.
//

auto Plan9Options = std::format("{};path={}", PLAN9_ANAME_DRVFS, Plan9Source);

//
// N.B. The cache option is added to the start of this so if the user
// specifies one explicitly, it will override the default.
//

std::string MountOptions = "cache=mmap,";
auto ParsedOptions = ConvertDrvfsMountOptionsToPlan9(Options ? Options : "", Config);
Plan9Options += ParsedOptions.first;
MountOptions += ParsedOptions.second;

//
// Append the 9p mount options to the end of the other mount options and perform the mount operation.
//

MountOptions += Plan9Options;

if (MountPlan9Filesystem(Source, Target, MountOptions.c_str(), Elevated, Config, ExitCode) < 0)
{
return -1;
}

return 0;
return MountPlan9(Source, Target, Options, Admin, Config, ExitCode);
}
CATCH_RETURN_ERRNO()

Expand Down Expand Up @@ -407,7 +349,7 @@ Return Value:
return ExitCode;
}

int MountPlan9Filesystem(const char* Source, const char* Target, const char* Options, bool Admin, const wsl::linux::WslDistributionConfig& Config, int* ExitCode)
int MountPlan9Share(const char* Source, const char* Target, const char* Options, bool Admin, const wsl::linux::WslDistributionConfig& Config, int* ExitCode)

/*++
Expand All @@ -425,6 +367,8 @@ Routine Description:
Admin - Supplies a boolean specifying if the admin share should be used.
Config - Supplies the distribution configuration.
ExitCode - Supplies an optional pointer that receives the exit code.
Return Value:
Expand Down Expand Up @@ -452,10 +396,95 @@ Return Value:

MountOptions =
std::format("msize={},trans=fd,rfdno={},wfdno={},{}", LX_INIT_UTILITY_VM_PLAN9_BUFFER_SIZE, Fd.get(), Fd.get(), Options);

return MountFilesystem(PLAN9_FS_TYPE, Source, Target, MountOptions.c_str(), ExitCode);
}
}

int MountPlan9(const char* Source, const char* Target, const char* Options, std::optional<bool> Admin, const wsl::linux::WslDistributionConfig& Config, int* ExitCode)

/*++
Routine Description:
This routine will perform a DrvFs mount using Plan9.
Arguments:
Source - Supplies the mount source.
Target - Supplies the mount target.
Options - Supplies the mount options.
Admin - Supplies an optional boolean to specify if the admin or non-admin share should be used.
Config - Supplies the distribution configuration.
ExitCode - Supplies an optional pointer that receives the exit code.
Return Value:
0 on success, -1 on failure.
--*/

try
{
//
// Check if the path is a UNC path.
//

const char* Plan9Source;
std::string UncSource;
if ((strlen(Source) >= PLAN9_UNC_PREFIX_LENGTH) && ((Source[0] == '/') || (Source[0] == '\\')) &&
((Source[1] == '/') || (Source[1] == '\\')))
{
UncSource = PLAN9_UNC_TRANSLATED_PREFIX;
UncSource += &Source[PLAN9_UNC_PREFIX_LENGTH];
Plan9Source = UncSource.c_str();
}
else
{
Plan9Source = Source;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This means Plan9Source has the potential of being null / empty. Could this cause issues with the "path=" option being set up on line 462?

}

//
// Check whether to use the elevated or regular 9p server.
//

bool Elevated = Admin.has_value() ? Admin.value() : IsDrvfsElevated();

//
// Initialize mount options.
//

auto Plan9Options = std::format("{};path={}", PLAN9_ANAME_DRVFS, Plan9Source);

//
// N.B. The cache option is added to the start of this so if the user
// specifies one explicitly, it will override the default.
//

std::string MountOptions = "cache=mmap,";
auto ParsedOptions = ConvertDrvfsMountOptionsToPlan9(Options ? Options : "", Config);
Plan9Options += ParsedOptions.first;
MountOptions += ParsedOptions.second;

//
// Append the 9p mount options to the end of the other mount options and perform the mount operation.
//

MountOptions += Plan9Options;
if (MountPlan9Share(Source, Target, MountOptions.c_str(), Elevated, Config, ExitCode) < 0)
{
return -1;
}

return 0;
}
CATCH_RETURN_ERRNO()

int MountVirtioFs(const char* Source, const char* Target, const char* Options, std::optional<bool> Admin, const wsl::linux::WslDistributionConfig& Config, int* ExitCode)

/*++
Expand Down Expand Up @@ -486,8 +515,6 @@ Return Value:

try
{
assert(wsl::shared::string::IsDriveRoot(Source));

//
// Check whether to use the elevated or non-elevated virtiofs server.
//
Expand Down Expand Up @@ -516,7 +543,7 @@ try
AddShare.WriteString(AddShare->OptionsOffset, Plan9Options);

//
// Connect to the wsl service to add the virtiofs share.
// Connect to the wsl service to add the virtiofs share. If adding the share fails, fallback to mounting using Plan9.
//

wsl::shared::SocketChannel Channel{UtilConnectVsock(LX_INIT_UTILITY_VM_VIRTIOFS_PORT, true), "VirtoFs"};
Expand All @@ -527,11 +554,10 @@ try

gsl::span<gsl::byte> ResponseSpan;
const auto& Response = Channel.Transaction<LX_INIT_ADD_VIRTIOFS_SHARE_MESSAGE>(AddShare.Span(), &ResponseSpan);

if (Response.Result != 0)
{
LOG_ERROR("Add virtiofs share for {} failed {}", Source, Response.Result);
return -1;
LOG_WARNING("Add virtiofs share for {} failed {}, falling back to Plan9", Source, Response.Result);
return MountPlan9(Source, Target, Options, Admin, Config, ExitCode);
}

//
Expand Down Expand Up @@ -596,3 +622,52 @@ try
return MountWithRetry(Tag, Target, VIRTIO_FS_TYPE, Options);
}
CATCH_RETURN_ERRNO()

std::string QueryVirtiofsMountSource(const char* Tag)

/*++
Routine Description:
This routine takes a virtiofs tag and determines the Windows path it refers to.
Arguments:
Tag - Supplies the virtiofs tag to query.
Return Value:
The mount source, an empty string on failure.
--*/

try
{
wsl::shared::MessageWriter<LX_INIT_QUERY_VIRTIOFS_SHARE_MESSAGE> QueryShare(LxInitMessageQueryVirtioFsDevice);
QueryShare.WriteString(QueryShare->TagOffset, Tag);

//
// Connect to the host and send the query request.
//

wsl::shared::SocketChannel Channel{UtilConnectVsock(LX_INIT_UTILITY_VM_VIRTIOFS_PORT, true), "QueryVirtioFs"};
if (Channel.Socket() < 0)
{
return {};
}

gsl::span<gsl::byte> ResponseSpan;
const auto& Response = Channel.Transaction<LX_INIT_QUERY_VIRTIOFS_SHARE_MESSAGE>(QueryShare.Span(), &ResponseSpan);
if (Response.Result != 0)
{
LOG_ERROR("Query virtiofs share for {} failed {}", Tag, Response.Result);
return {};
}

return wsl::shared::string::FromSpan(ResponseSpan, Response.TagOffset);
}
catch (...)
{
LOG_CAUGHT_EXCEPTION();
return {};
}
7 changes: 5 additions & 2 deletions src/linux/init/drvfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,12 @@ int MountDrvfs(const char* Source, const char* Target, const char* Options, std:

int MountDrvfsEntry(int Argc, char* Argv[]);

int MountPlan9Filesystem(
const char* Source, const char* Target, const char* Options, bool Admin, const wsl::linux::WslDistributionConfig& Config, int* ExitCode = nullptr);
int MountPlan9Share(const char* Source, const char* Target, const char* Options, bool Admin, const wsl::linux::WslDistributionConfig& Config, int* ExitCode = nullptr);

int MountPlan9(const char* Source, const char* Target, const char* Options, std::optional<bool> Admin, const wsl::linux::WslDistributionConfig& Config, int* ExitCode);

int MountVirtioFs(const char* Source, const char* Target, const char* Options, std::optional<bool> Admin, const wsl::linux::WslDistributionConfig& Config, int* ExitCode = nullptr);

int RemountVirtioFs(const char* Tag, const char* Target, const char* Options, bool Admin);

std::string QueryVirtiofsMountSource(const char* Tag);
38 changes: 2 additions & 36 deletions src/linux/init/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -902,11 +902,12 @@ try
}
else if (strcmp(MountEnum.Current().FileSystemType, VIRTIO_FS_TYPE) == 0)
{
MountSource = UtilParseVirtiofsMountSource(MountEnum.Current().Source);
MountSource = QueryVirtiofsMountSource(MountEnum.Current().Source);
if (MountSource.empty())
{
continue;
}

MountEnum.Current().Source = MountSource.data();
}
else if (strcmp(MountEnum.Current().FileSystemType, DRVFS_FS_TYPE) == 0)
Expand Down Expand Up @@ -2026,41 +2027,6 @@ Return Value:
return {};
}

std::string UtilParseVirtiofsMountSource(std::string_view Source)

/*++
Routine Description:
This routine parses the mount source to determine the actual source of a
a VirtioFs mount.
Arguments:
Source - Supplies the source string.
Return Value:
The mount source, or NULL if the source is not valid.
--*/

{
std::string MountSource{};
if (wsl::shared::string::StartsWith(Source, LX_INIT_DRVFS_ADMIN_VIRTIO_TAG) && (Source.size() >= sizeof(LX_INIT_DRVFS_ADMIN_VIRTIO_TAG)))
{
MountSource = Source[sizeof(LX_INIT_DRVFS_ADMIN_VIRTIO_TAG) - 1];
MountSource += ":";
}
else if (wsl::shared::string::StartsWith(Source, LX_INIT_DRVFS_VIRTIO_TAG) && (Source.size() >= sizeof(LX_INIT_DRVFS_VIRTIO_TAG)))
{
MountSource = Source[sizeof(LX_INIT_DRVFS_VIRTIO_TAG) - 1];
MountSource += ":";
}

return MountSource;
}

std::vector<char> UtilParseWslEnv(char* NtEnvironment)

/*++
Expand Down
Loading