libmodprobe: add support to remove modules
Add a remove method which will unload a given module from the kernel, along with any modules it depended on, assuming those modules are now unused. Change-Id: Ie66dc153ef1771f50e26421d38d3656e95954780
This commit is contained in:
parent
73b2928b94
commit
bb58b01574
5 changed files with 58 additions and 0 deletions
|
@ -26,11 +26,13 @@ class Modprobe {
|
|||
|
||||
bool LoadListedModules();
|
||||
bool LoadWithAliases(const std::string& module_name, bool strict);
|
||||
bool Remove(const std::string& module_name);
|
||||
|
||||
private:
|
||||
std::string MakeCanonical(const std::string& module_path);
|
||||
bool InsmodWithDeps(const std::string& module_name);
|
||||
bool Insmod(const std::string& path_name);
|
||||
bool Rmmod(const std::string& module_name);
|
||||
std::vector<std::string> GetDependencies(const std::string& module);
|
||||
bool ModuleExists(const std::string& module_name);
|
||||
|
||||
|
|
|
@ -315,3 +315,18 @@ bool Modprobe::LoadListedModules() {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Modprobe::Remove(const std::string& module_name) {
|
||||
auto dependencies = GetDependencies(MakeCanonical(module_name));
|
||||
if (dependencies.empty()) {
|
||||
LOG(ERROR) << "Empty dependencies for module " << module_name;
|
||||
return false;
|
||||
}
|
||||
if (!Rmmod(dependencies[0])) {
|
||||
return false;
|
||||
}
|
||||
for (auto dep = dependencies.begin() + 1; dep != dependencies.end(); ++dep) {
|
||||
Rmmod(*dep);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -51,6 +51,15 @@ bool Modprobe::Insmod(const std::string& path_name) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Modprobe::Rmmod(const std::string& module_name) {
|
||||
int ret = syscall(__NR_delete_module, MakeCanonical(module_name).c_str(), O_NONBLOCK);
|
||||
if (ret != 0) {
|
||||
PLOG(ERROR) << "Failed to remove module '" << module_name << "'";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Modprobe::ModuleExists(const std::string& module_name) {
|
||||
struct stat fileStat;
|
||||
auto deps = GetDependencies(module_name);
|
||||
|
|
|
@ -51,6 +51,16 @@ bool Modprobe::Insmod(const std::string& path_name) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Modprobe::Rmmod(const std::string& module_name) {
|
||||
for (auto it = modules_loaded.begin(); it != modules_loaded.end(); it++) {
|
||||
if (*it == module_name) {
|
||||
modules_loaded.erase(it);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Modprobe::ModuleExists(const std::string& module_name) {
|
||||
auto deps = GetDependencies(module_name);
|
||||
if (deps.empty()) {
|
||||
|
|
|
@ -56,6 +56,14 @@ TEST(libmodprobe, Test) {
|
|||
"/test13.ko",
|
||||
};
|
||||
|
||||
std::vector<std::string> expected_after_remove = {
|
||||
"/test14.ko", "/test15.ko", "/test1.ko",
|
||||
"/test6.ko", "/test2.ko", "/test5.ko",
|
||||
"/test8.ko", "/test7.ko param1=4", "/test9.ko param_x=1 param_y=2 param_z=3",
|
||||
"/test10.ko", "/test12.ko", "/test11.ko",
|
||||
"/test13.ko",
|
||||
};
|
||||
|
||||
const std::string modules_dep =
|
||||
"test1.ko:\n"
|
||||
"test2.ko:\n"
|
||||
|
@ -131,4 +139,18 @@ TEST(libmodprobe, Test) {
|
|||
}
|
||||
|
||||
EXPECT_TRUE(modules_loaded == expected_modules_loaded);
|
||||
|
||||
EXPECT_TRUE(m.Remove("test4"));
|
||||
|
||||
GTEST_LOG_(INFO) << "Expected modules loaded after removing test4 (in order):";
|
||||
for (auto i = expected_after_remove.begin(); i != expected_after_remove.end(); ++i) {
|
||||
*i = dir.path + *i;
|
||||
GTEST_LOG_(INFO) << "\"" << *i << "\"";
|
||||
}
|
||||
GTEST_LOG_(INFO) << "Actual modules loaded after removing test4 (in order):";
|
||||
for (auto i = modules_loaded.begin(); i != modules_loaded.end(); ++i) {
|
||||
GTEST_LOG_(INFO) << "\"" << *i << "\"";
|
||||
}
|
||||
|
||||
EXPECT_TRUE(modules_loaded == expected_after_remove);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue