Skip to content

Commit 31e51de

Browse files
reddevillgdengbo11
authored andcommitted
fix: improve detect kenrel overlay support
Detect kenrel overlay support by /proc/filesystems, modinfo and scan module file. Signed-off-by: reddevillg <reddevillg@gmail.com>
1 parent f0415e4 commit 31e51de

5 files changed

Lines changed: 167 additions & 28 deletions

File tree

libs/linglong/src/linglong/runtime/overlayfs_driver.cpp

Lines changed: 127 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,101 @@
66

77
#include "linglong/runtime/overlayfs_driver.h"
88

9+
#include "linglong/utils/cmd.h"
910
#include "linglong/utils/file.h"
1011

12+
#include <array>
1113
#include <fstream>
12-
#include <regex>
14+
15+
#include <sys/utsname.h>
1316

1417
namespace linglong::runtime {
18+
namespace {
19+
20+
auto filesystemHasOverlay() noexcept -> bool
21+
{
22+
std::ifstream filesystems("/proc/filesystems");
23+
if (!filesystems.is_open()) {
24+
return false;
25+
}
26+
27+
std::string line;
28+
while (std::getline(filesystems, line)) {
29+
if (line.find("overlay") != std::string::npos) {
30+
return true;
31+
}
32+
}
33+
34+
return false;
35+
}
36+
37+
auto modinfoHasOverlay() noexcept -> bool
38+
{
39+
auto modinfo = utils::Cmd("modinfo");
40+
if (!modinfo.exists()) {
41+
return false;
42+
}
43+
44+
return modinfo.exec({ "overlay" }).has_value();
45+
}
46+
47+
auto overlayModuleExists() noexcept -> bool
48+
{
49+
struct utsname uts{};
50+
if (uname(&uts) != 0) {
51+
return false;
52+
}
53+
54+
const auto modulesRoot = std::filesystem::path("/lib/modules") / uts.release;
55+
const auto overlayModuleDir = modulesRoot / "kernel" / "fs" / "overlayfs";
56+
constexpr std::array<std::string_view, 4> overlayModules{
57+
"overlay.ko",
58+
"overlay.ko.gz",
59+
"overlay.ko.xz",
60+
"overlay.ko.zst",
61+
};
62+
63+
std::error_code ec;
64+
for (const auto module : overlayModules) {
65+
if (std::filesystem::exists(overlayModuleDir / module, ec)) {
66+
return true;
67+
}
68+
}
69+
70+
for (const auto &index : { "modules.dep", "modules.builtin" }) {
71+
std::ifstream modulesIndex(modulesRoot / index);
72+
if (!modulesIndex.is_open()) {
73+
continue;
74+
}
75+
76+
std::string line;
77+
while (std::getline(modulesIndex, line)) {
78+
if (line.find("kernel/fs/overlayfs/overlay.ko") != std::string::npos) {
79+
return true;
80+
}
81+
}
82+
}
83+
84+
return false;
85+
}
86+
87+
auto kernelVersionSupportsUserNamespaceOverlay() noexcept -> bool
88+
{
89+
struct utsname uts{};
90+
if (uname(&uts) != 0) {
91+
return false;
92+
}
93+
94+
int major = 0;
95+
int minor = 0;
96+
if (std::sscanf(uts.release, "%d.%d", &major, &minor) == 2) {
97+
return major > 5 || (major == 5 && minor >= 11);
98+
}
99+
100+
return false;
101+
}
102+
103+
} // namespace
15104

16105
auto OverlayFSDriver::create(utils::OverlayMode mode) noexcept -> std::unique_ptr<OverlayFSDriver>
17106
{
@@ -34,31 +123,9 @@ auto OverlayFSDriver::detectKernelOverlaySupport() noexcept -> OverlaySupport
34123
{
35124
OverlaySupport support{ false, false, false };
36125

37-
std::ifstream filesystems("/proc/filesystems");
38-
if (filesystems.is_open()) {
39-
std::string line;
40-
while (std::getline(filesystems, line)) {
41-
if (line.find("overlay") != std::string::npos) {
42-
support.kernelAvailable = true;
43-
break;
44-
}
45-
}
46-
}
47-
48-
std::ifstream version("/proc/version");
49-
if (version.is_open()) {
50-
std::string line;
51-
std::getline(version, line);
52-
std::regex versionRegex("Linux version (\\d+)\\.(\\d+)");
53-
std::smatch match;
54-
if (std::regex_search(line, match, versionRegex) && match.size() > 2) {
55-
int major = std::stoi(match[1]);
56-
int minor = std::stoi(match[2]);
57-
if (major > 5 || (major == 5 && minor >= 11)) {
58-
support.kernelVersionOK = true;
59-
}
60-
}
61-
}
126+
support.kernelAvailable =
127+
filesystemHasOverlay() || modinfoHasOverlay() || overlayModuleExists();
128+
support.kernelVersionOK = kernelVersionSupportsUserNamespaceOverlay();
62129

63130
support.canUseInUserNS = support.kernelAvailable && support.kernelVersionOK;
64131
return support;
@@ -69,6 +136,40 @@ auto OverlayFSDriver::canUseKernelOverlay() noexcept -> bool
69136
return detectKernelOverlaySupport().canUseInUserNS;
70137
}
71138

139+
auto OverlayFSDriver::canUseFUSEOverlay() noexcept -> bool
140+
{
141+
return utils::Cmd("fuse-overlayfs").exists();
142+
}
143+
144+
auto OverlayFSDriver::resolveOverlayMode(utils::OverlayMode mode) noexcept
145+
-> utils::error::Result<utils::OverlayMode>
146+
{
147+
LINGLONG_TRACE("resolve overlayfs mode");
148+
149+
switch (mode) {
150+
case utils::OverlayMode::Kernel:
151+
if (canUseKernelOverlay()) {
152+
return utils::OverlayMode::Kernel;
153+
}
154+
return LINGLONG_ERR("kernel overlayfs is unavailable");
155+
case utils::OverlayMode::FUSE:
156+
if (canUseFUSEOverlay()) {
157+
return utils::OverlayMode::FUSE;
158+
}
159+
return LINGLONG_ERR("fuse-overlayfs command is unavailable");
160+
case utils::OverlayMode::Auto:
161+
if (canUseKernelOverlay()) {
162+
return utils::OverlayMode::Kernel;
163+
}
164+
if (canUseFUSEOverlay()) {
165+
return utils::OverlayMode::FUSE;
166+
}
167+
return LINGLONG_ERR("no available overlayfs implementation");
168+
}
169+
170+
return LINGLONG_ERR("unknown overlayfs mode");
171+
}
172+
72173
auto OverlayFSDriver::modeToString(utils::OverlayMode mode) noexcept -> std::string_view
73174
{
74175
return utils::overlayModeToString(mode);

libs/linglong/src/linglong/runtime/overlayfs_driver.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ class OverlayFSDriver
3737
static auto create(utils::OverlayMode mode) noexcept -> std::unique_ptr<OverlayFSDriver>;
3838
static auto detectKernelOverlaySupport() noexcept -> OverlaySupport;
3939
static auto canUseKernelOverlay() noexcept -> bool;
40+
static auto canUseFUSEOverlay() noexcept -> bool;
41+
static auto resolveOverlayMode(utils::OverlayMode mode) noexcept
42+
-> utils::error::Result<utils::OverlayMode>;
4043
static auto modeToString(utils::OverlayMode mode) noexcept -> std::string_view;
4144
static auto modeFromString(std::string_view mode) noexcept
4245
-> utils::error::Result<utils::OverlayMode>;

libs/linglong/src/linglong/runtime/run_context.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -636,8 +636,12 @@ utils::error::Result<void> RunContext::resolveOverlayMode(std::optional<std::str
636636
mode = *parsedMode;
637637
}
638638

639-
auto driver = OverlayFSDriver::create(mode);
640-
contextCfg.overlayfs = std::string(OverlayFSDriver::modeToString(driver->mode()));
639+
auto resolvedMode = OverlayFSDriver::resolveOverlayMode(mode);
640+
if (!resolvedMode) {
641+
return LINGLONG_ERR("resolve overlayfs mode", resolvedMode);
642+
}
643+
644+
contextCfg.overlayfs = std::string(OverlayFSDriver::modeToString(*resolvedMode));
641645

642646
return LINGLONG_OK;
643647
}

libs/linglong/tests/ll-tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ pfl_add_executable(
5252
src/linglong/repo/ostree_repo_test.cpp
5353
src/linglong/repo/repo_cache_test.cpp
5454
src/linglong/runtime/container_builder_test.cpp
55+
src/linglong/runtime/overlayfs_driver_test.cpp
5556
src/linglong/runtime/run_context_test.cpp
5657
src/linglong/utils/bash_command_helper_test.cpp
5758
src/linglong/utils/cmd_test.cpp

libs/linglong/tests/ll-tests/src/linglong/runtime/overlayfs_driver_test.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include "common/tempdir.h"
88
#include "linglong/runtime/overlayfs_driver.h"
9+
#include "linglong/utils/cmd.h"
910

1011
#include <filesystem>
1112

@@ -57,6 +58,35 @@ TEST(OverlayFSDriverStatic, CanUseKernelOverlay)
5758
std::cout << "canUseKernelOverlay: " << (canUse ? "yes" : "no") << std::endl;
5859
}
5960

61+
TEST(OverlayFSDriverStatic, CanUseFUSEOverlay)
62+
{
63+
bool canUse = linglong::runtime::OverlayFSDriver::canUseFUSEOverlay();
64+
65+
EXPECT_EQ(canUse, linglong::utils::Cmd("fuse-overlayfs").exists())
66+
<< "canUseFUSEOverlay should reflect fuse-overlayfs command availability";
67+
68+
std::cout << "canUseFUSEOverlay: " << (canUse ? "yes" : "no") << std::endl;
69+
}
70+
71+
TEST(OverlayFSDriverStatic, ResolveOverlayMode)
72+
{
73+
auto support = linglong::runtime::OverlayFSDriver::detectKernelOverlaySupport();
74+
auto fuseAvailable = linglong::runtime::OverlayFSDriver::canUseFUSEOverlay();
75+
76+
auto resolvedMode =
77+
linglong::runtime::OverlayFSDriver::resolveOverlayMode(linglong::utils::OverlayMode::Auto);
78+
79+
if (support.canUseInUserNS) {
80+
ASSERT_TRUE(resolvedMode);
81+
EXPECT_EQ(*resolvedMode, linglong::utils::OverlayMode::Kernel);
82+
} else if (fuseAvailable) {
83+
ASSERT_TRUE(resolvedMode);
84+
EXPECT_EQ(*resolvedMode, linglong::utils::OverlayMode::FUSE);
85+
} else {
86+
EXPECT_FALSE(resolvedMode);
87+
}
88+
}
89+
6090
TEST_F(OverlayFSDriverTest, AutoModeSelection)
6191
{
6292
auto driver = linglong::runtime::OverlayFSDriver::create(linglong::utils::OverlayMode::Auto);

0 commit comments

Comments
 (0)